74

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

 5 years ago
source link: http://zhuanlan.51cto.com/art/201808/581048.htm?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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

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

NbMraiM.jpg!web

什么是内存

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

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

物理内存

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

虚拟内存

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

Swap分区

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

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

查看内存使用情况

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

free命令

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

$free 
             total       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 
em:       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 行

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

Total:16777208。Swap内存总大小。

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

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

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

$free 
             total       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 -m 
             total       used       free     shared    buffers     cached 
Mem:          8192       2802       5389          0          0       1559 
-/+ buffers/cache:       1243       6948 
Swap:        16383          0      16383 

-g 以G为单位显示内存

$free -g 
             total       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 2 
         total       used       free     shared    buffers     cached 
Mem:       8388608    2873128    5515480          0          0    1600588 
-/+ buffers/cache:    1272540    7116068 
Swap:     16777208          0   16777208 
 
             total       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 cached 
 
   PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND 
 85690 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。

➜  ~ top 
 
PID 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文件后,可以进行对象分析。如果有大量对象在持续被引用,并没有被释放掉,那就产生了内存泄露,就要结合代码,把不用的对象释放掉。

【本文是51CTO专栏作者Hollis的原创文章,作者微信公众号Hollis(ID:hollischuang)】

戳这里,看该作者更多好文


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK