在平时的工作中,衡量服务器性能时,往往会涉及到几个指标,比如load、cpu、mem、qps、rt等,每个指标都有其独特的含义。很多时候线上出现问题的时候,往往伴随着某些指标的异常。在大多数情况下,某些指标会在问题发生之前提前显示异常。在第一篇文章中,我们介绍了一个重要的指标就是负载(Load)。我们提到Linux的高负载主要是三个部分造成的:CPU占用、内存占用、IO消耗。过度使用任何一个都会导致服务器负载急剧增加。这篇文章是系列的第三篇,分析影响机器负载、内存使用的几个原因的第二篇。什么是内存内存是计算机中最重要的部件之一,是与CPU沟通的桥梁。计算机中的所有程序都运行在内存中,因此内存的性能对计算机的性能影响很大。内存(Memory),又称内存储器,是用来在CPU中暂存计算数据,并与硬盘等外部存储器进行数据交换的。物理内存物理内存是指通过物理内存条获得的内存空间。即随机存取存储器(randomaccessmemory,RAM),是一种直接与CPU进行数据交换的内部存储器,也称为主存(memory)。虚拟内存虚拟内存是一种用于计算机系统内存管理的技术。它让应用程序以为自己有连续的可用内存(连续且完整的地址空间),但实际上,它通常被分成多个物理内存碎片,有的暂时存放在外部磁盘存储中。进行数据交换(即当物理内存不足时,可能会借用硬盘空间作为内存占用)。使用这种技术的系统比不使用虚拟内存技术的系统更容易编写大型程序并更有效地使用真实的物理内存(如RAM)。Swap分区Swap分区(即交换区)在系统的物理内存不够用时,释放一部分硬盘空间供当前运行的程序使用。释放出来的空间可能来自于一些很久没有运行的程序。这些释放出来的空间暂时保存在Swap分区中,当那些程序要运行时,保存的数据从Swap分区恢复到内存中。程序运行时的数据加载、线程并发、I/O缓冲等,都依赖于内存,而可用内存的大小决定了程序能否正常运行及其性能。查看内存使用情况在Linux机器上,有多个命令可以查看机器的内存信息。这些包括免费,顶级等。free命令free命令可以显示Linux系统中空闲和使用的物理内存、swap分区和内核缓冲内存。在Linux系统监控工具中,free命令是使用频率最高的命令之一。$freetotalusedfreesharedbufferscachedMem:838860829269685461640001654392-/+buffers/cache:12725767116032Swap:16777208016777208上图中有3行6列的数据。rowdata的含义如下:Memrow是内存使用量。-/+buffers/cacheline是物理内存的缓存统计信息。Swap行是交换空间的使用情况。前面介绍了物理内存和Swap分区。这里再介绍一下buffer和cache。缓冲区和高速缓存之间的区别缓冲区是尚未“写入”磁盘的东西。缓存是从磁盘“读取”并存储以备后用的东西。简单来说:buffer是存放要输出到磁盘(Blockdevice)的数据,buffer写满一次,提高IO性能(内存->磁盘)cached是存放从磁盘读取的数据,常用到cache,reduceIO(磁盘->内存)buffer和cache,都是RAM中的数据。简单的说就是buffer即将写入磁盘,cache从磁盘读取。介绍完buffer和cache的区别,我们来分析一下free命令查询到的数据。mem行totalusedfreesharedbufferscachedem:838860829269685461640001654392这一行显示了物理内存的整体情况。Total:8388608。表示物理内存的总大小。Used:2926968。表示分配给缓存的总量(包括buffer和cache),但有些cache可能没有实际使用。空闲:5461640。表示未分配的内存。共享:0。一般系统不使用共享内存。Buffers:0.系统分配但未使用的缓冲区数。Cached:1654392.系统分配但未使用的缓存量。total(Mem)=used(Mem)+free(Mem)-/+buffers/cache行totalusedfreesharedbufferscached-/+buffers/cache:12725767116032Used:1272576。表示实际使用的缓冲区和缓存总量,以及实际使用的内存总量。空闲:7116032。未使用的缓冲区、缓存和未分配内存的总和是系统实际可用的内存。used(-/+buffers/cache)=used(Mem)-cached(Mem)-buffers(Mem)free(-/+buffers/cache)=free(Mem)+cached(Mem)+buffers(Mem)交换线$freetotalusedfreesharedbufferscachedSwap:16777208016777208Total:16777208。交换内存的总大小。Used:0。表示分配的Swap大小。空闲:16777208。表示未分配的内存。接下来,让我们整体来看一下数据。$freetotalusedFreesharedBuffersCachedMem:838860829269685461640001654392-/+buffers/cache:12725767116032Swap:1677772080167777777208频繁;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。在分配的2,926,968个中,1,654,392个未使用,1,272,576个已使用。当前机器还有7116032内存可用。free命令参数-m以M为单位显示内存$free-mtotalusedfreesharedbufferscachedMem:819228025389001559-/+buffers/cache:12436948Swap:16383016383-g以G为单位显示内存$free-gtotalusedfreesharedbufferscachedMem:8250/p+cachedMem:8250-s162持续的观察内存的状况,每隔2秒打印一次$free-s2totalusedfreesharedbufferscachedMem:838860828731285515480001600588-/+buffers/cache:12725407116068Swap:16777208016777208totalusedfreesharedbufferscachedMem:838860828731685515440001600628-/+buffers/cache:12725407116068Swap:16777208016777208除了free,还可以UnderLinux,您可以使用/proc/meminfo文件来查看操作系统内存的使用情况。事实上,free命令的内容也来自于/proc/meminfo文件。top命令top命令是Linux下常用的性能分析工具。它可以实时显示系统中各个进程的资源使用情况,类似于Windows的任务管理器。在前面两篇文章中,我们介绍了使用top命令查看LoadAvg和CPU利用率。top也会打印的部分信息是内存情况。top-17:49:32up2days,6:25,1user,loadaverage:0.01,0.09,0.12Tasks:30total,1running,29sleeping,0stopped,0zombieCpu(s):0.1%us,0.0%sy,0.0%ni,88.0%id,3.8%wa,0.0%hi,0.0%si,8.1%stMem:8388608ktotal,2884716kused,5503892kfree,0kbuffersSwap:16777208ktotal,0kused,16777208kfree,1612080kcachedPIDUSERPRNIVIRTRESSHRS%CPU%MEMTIME+COMMAND85690admin2005138m1.1g47mS2.313.993:28.92java上面的Mem行Swap行显示内存使用情况。并且还会根据进度显示不同进程的内存使用情况。非常容易使用。Javaweb应用内存占用飙升,排查思路是JVM作为进程(Process)运行在Linux系统上。对于Linux来说,JVM只是一个自我管理内存的好孩子。一般JVM内存的大小可以在应用程序启动时通过JVM参数设置。如果超出此限制,则会抛出异常。所以内存占用高最常见的问题就是抛出各种OutOfMemoryError。有一种情况可能会导致直接内存,就是Linux的物理内存过高,这就是NIO的使用。NIO引入了一种基于通道和缓冲区的IO方法。它可以使用Native函数库直接分配堆外内存,然后使用Java堆中存储的一个DirectByteBuffer对象作为对这块内存的引用。所以在使用NIO的时候要非常小心,避免造成机器内存拥挤。JVM内存占用高的原因可能有很多。最常见的是内存泄漏。内存泄漏排查思路1、使用top命令查看内存占用高的进程号。?~topPIDUSERPRNIVIRTRESSHRS%CPU%MEMTIME+COMMAND3331admin2007127m2.6g38mS10.790.610:20.26java发现PID为3331的进程占用了90.6%的内存。而且是Java进程,基本确定是程序问题。2、使用jmap查看内存情况,分析是否存在内存泄漏。jmap-heap3331:查看java堆(heap)的使用情况jmap-histo3331:查看堆内存中对象的数量和大小(直方图)jmap-histo:live3331:JVM会先触发gc,然后统计信息jmap-dump:format=b,file=heapDump3331:将内存使用的详细信息输出到一个文件中得到heapdump文件后,就可以进行对象分析了。如果大量的对象被持续引用而没有释放,就会发生内存泄漏,必须结合代码释放不用的对象。【本文为专栏作家霍利斯原创文章,作者微信公众号Hollis(ID:hollishuang)】点此阅读更多本作者好文
