线上服务器内存分析及问题排查

转载自  线上服务器内存分析及问题排查

平常的工作中,在衡量服务器的性能时,经常会涉及到几个指标,load、cpu、mem、qps、rt等。每个指标都有其独特的意义,很多时候在线上出现问题时,往往会伴随着某些指标的异常。大部分情况下,在问题发生之前,某些指标就会提前有异常显示。

在第一篇文章中,我们介绍了一个重要的指标就是负载(Load),其中我们提到Linux的负载高,主要是由于CPU使用、内存使用、IO消耗三部分构成。任意一项使用过多,都将导致服务器负载的急剧攀升。本文是该系列的第三篇,来分析一下影响机器负载的几个原因中的第二项,内存使用。

 

什么是内存

内存是计算机中重要的部件之一,它是与CPU进行沟通的桥梁。计算机中所有程序的运行都是在内存中进行的,因此内存的性能对计算机的影响非常大。

内存(Memory)也被称为内存储器,其作用是用于暂时存放CPU中的运算数据,以及与硬盘等外部存储器交换的数据。

物理内存

物理内存指通过物理内存条而获得的内存空间。即随机存取存储器(random access memory,RAM),是与CPU直接交换数据的内部存储器,也叫主存(内存)。

虚拟内存

虚拟内存是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换(也就是说,当物理内存不足时,可能会借用硬盘空间来充当内存使用)。与没有使用虚拟内存技术的系统相比,使用这种技术的系统使得大型程序的编写变得更容易,对真正的物理内存(例如RAM)的使用也更有效率。

Swap分区

Swap分区(即交换区)在系统的物理内存不够用的时候,把硬盘空间中的一部分空间释放出来,以供当前运行的程序使用。那些被释放的空间可能来自一些很长时间没有什么操作的程序,这些被释放的空间被临时保存到Swap分区中,等到那些程序要运行时,再从Swap分区中恢复保存的数据到内存中。

程序运行时的数据加载,线程并发,I/O缓冲等等,都依赖于内存,可用内存的大小,决定了程序是否能正常运行以及运行的性能。

查看内存使用情况

在Linux机器上,有多个命令都可以查看机器的内存信息。其中包括free、top等。

free命令

free命令可以显示Linux系统中空闲的、已用的物理内存swap分区以及被内核缓冲区内存。在Linux系统监控的工具中,free命令是最经常使用的命令之一。

$freetotal       used       free     shared    buffers     cached
Mem:       8388608    2926968    5461640          0          0    1654392
-/+ buffers/cache:    1272576    7116032
Swap:     16777208          0   16777208

上图中,一共有3行6列数据,行数据的意义如下: Mem 行是内存的使用情况。 -/+ buffers/cache 行是物理内存的缓存统计情况。 Swap 行是交换空间的使用情况。

前面分别介绍过了物理内存和Swap分区。这里再介绍一下buffers和cache。

buffer与cache的区别

A buffer is something that has yet to be "written" to disk.

A cache is something that has been "read" from the disk and stored for later use.

简单点说:

buffers 就是存放要输出到disk(块设备)的数据,缓冲满了一次写,提高IO性能(内存 -> 磁盘)

cached 就是存放从disk上读出的数据,常用的缓存起来,减少IO(磁盘 -> 内存)

buffer 和 cache,两者都是RAM中的数据。简单来说,buffer是即将要被写入磁盘的,cache是被从磁盘中读出来的。

介绍完了buffer和cache的区别,接下来分析下free命令查询到的数据。

Mem行

             total       used       free     shared    buffers     cached
Mem:       8388608    2926968    5461640          0          0    1654392

这一行展示物理内存的整体情况。

Total:8388608。表示物理内存总大小。

Used :2926968。表示总计分配给缓存(包含buffers 与cache )使用的数量,但其中可能部分缓存并未实际使用。

Free :5461640。表示未被分配的内存。

Shared:0。共享内存,一般系统不会用到。

Buffers:0。系统分配但未被使用的buffers 数量。

Cached:1654392。系统分配但未被使用的cache 数量。

total(Mem) = used(Mem) + free(Mem)

-/+ buffers/cache 行

             total       used       free     shared    buffers     cached
-/+ buffers/cache:    1272576    7116032

Used:1272576。 表示实际使用的buffers 与cache 总量,也是实际使用的内存总量。

Free:7116032。 未被使用的buffers 与cache 和未被分配的内存之和,这就是系统当前实际可用内存。

used(-/+ buffers/cache) = used(Mem) - cached(Mem) - buffers(Mem)

free(-/+ buffers/cache) = free(Mem) + cached (Mem)+ buffers(Mem)

Swap 行

$freetotal       used       free     shared    buffers     cached
Swap:     16777208          0   16777208

Total:16777208。Swap内存总大小。

Used:0。表示已分配的Swap大小。

Free:16777208。表示未被分配的内存。

接下来,再来整体看一下数据

$freetotal       used       free     shared    buffers     cached
Mem:       8388608    2926968    5461640          0          0    1654392
-/+ buffers/cache:    1272576    7116032
Swap:     16777208          0   16777208

机器上实际可用内存大小:

   Free(-/+ buffers/cache)= Free(Mem)+buffers(Mem)+Cached(Mem);7116032 = 5461640 + 0+ 1654392

已经分配的内存大小:

   Used(Mem) = Used(-/+ buffers/cache)+ buffers(Mem) + Cached(Mem)2926968 = 1272576 + 0 + 1654392

物理内存总大小

   total(Mem) = used(-/+ buffers/cache) + free(-/+ buffers/cache)8388608 = 1272576 + 7116032

总结一下,整个机器的总内存大小8388608,其中已经分配的内存有2926968,还未分配的内存有5461640。而分配的2926968中,有1654392还没有使用,有1272576已经用掉了。当前机器中还有7116032内存可以使用。

free命令参数

-m 以M为单位显示内存

$free -mtotal       used       free     shared    buffers     cached
Mem:          8192       2802       5389          0          0       1559
-/+ buffers/cache:       1243       6948
Swap:        16383          0      16383

-g 以G为单位显示内存

$free -gtotal       used       free     shared    buffers     cached
Mem:          8          2          5         0         0           1
-/+ buffers/cache:       1          6
Swap:        16          0          16

-s 2持续的观察内存的状况,每隔2秒打印一次

$free -s 2total       used       free     shared    buffers     cached
Mem:       8388608    2873128    5515480          0          0    1600588
-/+ buffers/cache:    1272540    7116068
Swap:     16777208          0   16777208total       used       free     shared    buffers     cached
Mem:       8388608    2873168    5515440          0          0    1600628
-/+ buffers/cache:    1272540    7116068
Swap:     16777208          0   16777208

除了free ,还可以在Linux下可以使用/proc/meminfo文件查看操作系统内存的使用状态,其实,free命令的内容也是来自于/proc/meminfo文件。

top命令

top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器。

在前面两篇文章中介绍过使用top命令查看Load Avg和CPU利用率。top还会打印的一部分信息就是内存情况。

top - 17:49:32 up 2 days,  6:25,  1 user,  load average: 0.01, 0.09, 0.12
Tasks:  30 total,   1 running,  29 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.1%us,  0.0%sy,  0.0%ni, 88.0%id,  3.8%wa,  0.0%hi,  0.0%si,  8.1%st
Mem:   8388608k total,  2884716k used,  5503892k free,        0k buffers
Swap: 16777208k total,        0k used, 16777208k free,  1612080k cachedPID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND85690 admin     20   0 5138m 1.1g  47m S  2.3 13.9  93:28.92 java

上面的Mem行和Swap行展示的就是内存的使用情况。并且也会按照进行展示不同进程的内存占用情况。十分好用。

 

Java Web应用内存占用飙高排查思路

JVM以一个进程(Process)的身份运行在Linux系统上,对于Linux来说,JVM不过是一个具有自助管理内存的乖孩子而已。

一般在应用启动时都可以通过JVM参数来设置JVM内存的大小。如果超过这个限制就会抛出异常。所以,我们比较常见的内存占用过高问题,最显著的现象就是抛出各种OutOfMemoryError。

有一种可能导致直接内存,也就是Linux的物理内存过高的情况,就是NIO的使用。NIO引入了一种基于通道与缓冲区的IO方式,他可以使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。

所以,在使用NIO的时候,要特别小心,避免导致机器内存被挤满。

导致JVM中内存占用飙高的原因可能有很多。最常见的就是内存泄露。

内存泄露排查思路

1、使用top命令,查看占用内存较高的进程ID。

➜  ~ topPID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
3331 admin     20   0 7127m 2.6g  38m S 10.7 90.6  10:20.26 java

发现PID为3331的进程占用内存 90.6%。而且是一个Java进程,基本断定是程序问题。

2、使用jmap查看内存情况,并分析是否存在内存泄露。

jmap -heap 3331:查看java 堆(heap)使用情况jmap -histo 3331:查看堆内存(histogram)中的对象数量及大小jmap -histo:live 3331:JVM会先触发gc,然后再统计信息jmap -dump:format=b,file=heapDump 3331:将内存使用的详细情况输出到文件

得到堆dump文件后,可以进行对象分析。如果有大量对象在持续被引用,并没有被释放掉,那就产生了内存泄露,就要结合代码,把不用的对象释放掉。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/324925.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RabbitMQ系列教程之一:我们从最简单的事情开始!Hello World

一、简介 RabbitMQ是一个消息的代理器,用于接收和发送消息,你可以这样想,他就是一个邮局,当您把需要寄送的邮件投递到邮筒之时,你可以确定的是邮递员先生肯定会把邮件发送到需要接收邮件的人的手里,不…

红歌合唱之团结就是力量

今天,由王老师组织的班级红歌大合唱之“团结就是力量”圆满落幕!下面是整个合唱的视频,同学们个个都朝气蓬勃:以下是《团结就是力量》的全部歌词团结就是力量团结就是力量这力量是铁这力量是钢比铁还硬比钢还强向着法西斯蒂开火让…

Servlet API

1、书写一个servlet的方式 Servlet必须直接或间接实现 javax.servlet.Servlet 接口 通过继承javax.servlet.GenericServlet 类实现跨协议的 Servlet 通过继承javax.servlet.HttpServlet实现HTTP Servlet 自己定义个servlet,然后其他的java类都继承自己写好的servlet…

EventBus In eShop -- 解析微软微服务架构eShopOnContainers(四)

引言 大家好像对分析源码厌倦了,说实在我也会厌倦,不过不看是无法分析其后面的东西,从易到难是一个必要的过程。 今天说下EventBus,前几天园里的大神已经把其解刨事件总线(Event Bus)知多少,我…

基本数据类型、包装类、String三者之间的相互转换

package com.wdl.day13;import org.junit.Test;/** 包装类的使用:* 1.java提供了8种基本数据类型对应的包装类,使得基本数据类型的变量具有类的特征** 2.掌握的:基本数据类型、包装类、String三者之间的相互转换****/ public class WrapperTest {//Strin…

很简单很简单的DBHelper类

记录一个简单的DBHelper类吧&#xff0c;用的时候在上来拿&#xff01; /// <summary>/// 数据库连接工具类/// </summary>public class DBHelper{string constr "Data Source.;Initial CatalogschoolDB;Integrated SecurityTrue";private SqlConnecti…

DDD理论学习系列(1)-- 通用语言

1.引言 在开始之前&#xff0c;我想我们有必要先了解以下DDD的主要参与者。因为毕竟语言是人说的吗&#xff0c;就像我们面向对象编程一样&#xff0c;那通用语言面向的是&#xff1f;DDD的主要参与者&#xff1a;领域专家开发人员领域专家&#xff1a;精通业务的任何人。开发…

定了!对于本周四(7.16日)抽奖活动取消简要说明,新抽奖活动暂定下周三(7.22日)...

大家好&#xff0c;我是雄雄&#xff0c;对于本周四&#xff08;7.16日&#xff09;抽奖活动取消简要说明&#xff0c;新抽奖活动暂定下周三&#xff08;7.22日&#xff09;&#xff0c;欢迎各位粉丝积极参与&#xff0c;奖品已经准备好了&#xff0c;你&#xff01;准备好了吗…

RabbitMQ系列教程之二:工作队列(Work Queues)

今天开始RabbitMQ教程的第二讲&#xff0c;废话不多说&#xff0c;直接进入话题。 (使用.NET 客户端 进行事例演示) 在第一个教程中&#xff0c;我们编写了一个从命名队列中发送和接收消息的程序。在本教程中&#xff0c;我们将创建一个工作队列&#xff0c;这个队列将用于在…

面试中经常会问的智力题,来看看你会做几道

转载自 面试中经常会问的智力题&#xff0c;来看看你会做几道 下面是大部分题目来自滴滴出行2017秋招题。开始头脑风暴吧~~~ 问题 question one 有50家人家&#xff0c;每家一条狗。有一天警察通知&#xff0c;50条狗当中有病狗&#xff0c;行为和正常狗不一样。每人只能通…

你喜欢什么样的课堂?

最近看了一本书《让课堂充满幽默》&#xff0c;里面有些内容还是觉得挺有道理的。书中开头就说&#xff1a;“大量的课件、复杂的网络&#xff0c;使得老师似乎成了信息管理员和媒体播放机&#xff0c;学生则成为了被灌输的对象”&#xff0c;看后&#xff0c;内心深处反问自己…

main()方法

main()方法的使用说明&#xff1a; main()方法作为程序的入口main()方法也是一个普通的静态方法main()方法可以作为我们与控制台交互的方式。&#xff08;之前&#xff1a;使用Scanner&#xff09;

实现自己的.NET Core配置Provider之EF

《10分钟就能学会.NET Core配置》里详细介绍了.NET Core配置的用法&#xff0c;另外我还开源了自定义的配置Provider&#xff1a;EF配置Provider和Yaml配置Provider。本文先来聊聊EF配置Provider的实现&#xff0c;其中会涉及到EntityFramework Core的知识&#xff0c;不熟悉也…

今天的雪糕格外好吃!

赤日炎炎&#xff0c;室外的温度超过30℃。午休罢&#xff0c;教室里一片寂静&#xff0c;大家都有一个目的——等待老师的进来&#xff0c;继续上课。偶尔有几位同学貌似等待焦急&#xff0c;遂将目光瞥向窗外&#xff0c;若有所思。还有几位好动同学在自己的座位上左右摇动&a…

洛谷P2296-寻找道路【日常图论,最短路,SPFA】

题目 一个有向图&#xff0c;要求满足要求的最短路径&#xff0c;要求为&#xff1a; 路径上的所有点的出边所指向的点都直接或间接与终点连通。 输入1 3 2 (3个点,2条边) 1 2 (1和2之间可以连接) 2 1 1 3 (从1到3) 输出1 -1 输入2 6 6 1 2 1 3 2 6 2 5 4 5 3…

活动 | Unity带你亲临王者荣耀KPL总决赛,领略电竞的魅力

《王者荣耀》是由腾讯出品的 Made with Unity的现象级游戏。在Unite Shanghai 2017中的案例专场&#xff0c;我们也曾邀请了《王者荣耀》项目组的技术总监邓君&#xff0c;分享过《王者技术修炼之路》。 从移动游戏到电子竞技&#xff0c;KPL(King Pro League)也是《王者荣耀》…

Java的并发编程中的多线程问题到底是怎么回事儿?

转载自 Java的并发编程中的多线程问题到底是怎么回事儿&#xff1f; 在我之前的一篇《再有人问你Java内存模型是什么&#xff0c;就把这篇文章发给他。》文章中&#xff0c;介绍了Java内存模型&#xff0c;通过这篇文章&#xff0c;大家应该都知道了Java内存模型的概念以及作…

DDD理论学习系列(2)-- 领域

1. 引言 领域一词&#xff0c;主要有以下两个意思&#xff1a; 一国主权所达之地。学术思想或社会活动的范围。 不管是指国家的主权范围也好还是学术活动范围&#xff0c;都是在讲一个范围&#xff0c;一个界限。比如我们常说的&#xff0c;学术领域、思想领域、技术领域、语…

最全、最详细的配置jdk十步法!

求关注求转发大家好&#xff0c;我是雄雄。今天给大家分享的是 如何配置jdk &#xff0c;还记得我当年刚开始自学编程时&#xff0c;jdk配置了好几天才配置好&#xff0c;说来也是惭愧啊。并且配置成功的步骤我自己都不知道是啥&#xff0c;因为当时是东找一个方法&#xff0c;…

RabbitMQ系列教程之三:发布\/订阅(Publish\/Subscribe)

在前一个教程中&#xff0c;我们创建了一个工作队列。工作队列背后的假设是每个任务会被交付给一个【工人】。在这一部分我们将做一些完全不同的事情--我们将向多个【消费者】传递信息。这种模式被称为“发布/订阅”。 为了说明这种模式&#xff0c;我们将构建一个简单的日志…