东拉西扯的前奏:做java开发的程序员都知道,在java里不需要人工回收对象。所有清理对象的工作都由JVM来完成。
这一下子不得了,好多没有受过伤害的年轻人,就肆意妄为的创建对象,不分大小和能否复用,不分创建地点风水是否合时宜。
随手拈来,顺手牵去。经常导致程序部署到服务器后,发生内存溢出又或者是内存泄露的问题。而这类问题本身又不易立即显现,总是直到分配给程序的内存用尽后,才犹抱琵琶半遮面,崭露头角,让我们这些维护系统的人防不胜防,叫苦不堪。所以在程序部署到服务器以后的一段时间,监控程序占用的内存,成为提前发现这些隐晦问题的灵丹妙药。
接下来,我来介绍一下,一些linux服务器监控java程序内存的常用办法。
直接输入top指令回车,不用加其余参数,会有如下的展示界面:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
29115 root 15 0 2332 968 720 R 2.0 0.0 0:00.01 top
其中RES列的内容就是进程19115占用的内存值,当然这个值不是个单纯的内存值,但是这个值具备监控内存大小的价值,观察此值即可,当然喜欢折腾的同学可以深入的了解噢。
如果发现你部署的程序运行一段时间后,RES接近或者超过分配给应用的大小,这时就要密切关注这个进程了。而关注的方式,当然不是让你盯着top指令刷新的屏幕看哦,是要分析这个java进程的GC情况。
观察GC也有很多中方式,但是很多都需要安装一些系统不会自带的工具,又或者是图形化界面。这里介绍一个非常简单又非常有价值的工具,此工具为jstat,是jdk自带的一个分析java程序内存的工具,一般在服务器上都可以随地执行。
就像你会从不同角度了解一个人一样,jstat提供很多参数,帮助你从不同角度了解要监控的java进程。这个后续会专门写一篇博客详述。
这里我们通过命令:jstat -gcutil pid 1000 10 这条命令的意思是,查看进程号为PID的进程GC状态,没1秒钟刷新10条记录。
以下截取自一次真实的java进程GC分析。其中第7行时发生一次FGC后,发现O区域(老一代对象区域)的对象被回收从97.71%回落到27.11%,说明JVM可以正常回收内存。整个过程P区域(永久对象区域)的对象占有内存几乎没有升高,说明不会出现永久区内存溢出的问题。
当然观察这些数据要做持续不断的观察,只是偶然的一次FGC并不具备参考意义,这个命令最重要的指标就是FGC,如果连续观察,FGC发生的频率很高,并且每次FGC发生时O区域(老一代对象区域)中的内存回收率很低的话,恭喜你,有得玩了,那就真的可能有内存泄露发生。
$jstat -gcutil 36674 1000 10
S0 S1 E O P YGC YGCT FGC FGCT GCT
0.00 99.17 72.10 89.21 60.17 10437 257.685 60 82.855 340.540
0.00 99.17 72.74 89.21 60.17 10437 257.685 60 82.855 340.540
0.00 99.17 79.18 89.21 60.17 10437 257.685 60 82.855 340.540
0.00 11.44 93.02 89.82 60.17 10439 257.737 60 82.855 340.591
32.38 5.30 100.00 93.20 60.17 10442 257.810 60 82.855 340.664
0.00 13.85 100.00 93.21 60.17 10444 257.853 60 82.855 340.707
2.89 0.00 0.00 97.71 60.17 10444 257.945 61 82.855 340.800
0.00 0.00 45.80 27.11 60.18 10444 257.945 61 84.494 342.440
0.00 0.00 49.79 27.11 60.18 10444 257.945 61 84.494 342.440
0.00 0.00 50.34 27.11 60.18 10444 257.945 61 84.494 342.440
如果真的泄露了,怎么办?难道如热锅上的蚂蚁?(你猜对了,正式商用的系统上线后,发生内存泄露,一些不够淡定的同学一定会像热锅上的蚂蚁)
还是不要太担心,总有办法,车到山前必有路嘛。慌没有用地,哪怕一堆领导站在你后面批评,冷静才是最重要地。要如定海神针搬,屹立不动才能从容的解决问题。有些同学关键时刻,一出问题,就大脑无主,本来可以自己解决的问题,最后全都得依靠所谓的高手。
这里介绍一种方法,找出内存泄露来源,就是用jmap,同jstat,jmap也是jdk自带的工具,不需要额外安装。
同样我在后面会单独写文章阐述这个工具。
使用命令:jmap -dump:format=b,file=xx.bin pid 生成当前JVM内存的快照文件,xx.bin,然后下载下来,同eclipse MemoryAnalyzer工具(这个工具后续也同样详述)进行分析,此工具的Dominator可以展示出内存中每个对象占用的内存大小,并且列出所有的对象,如此这般哪个对象占用的内存最多,并且不释放,就一目了然。极好的是这个工具还可以看到内存对象中保存的数据,如,一个hashmap中保存的数据,这对我们找出代码中内存泄露的位置,有极大帮助。
这里先稍稍带过,欲了解此工具的详细用法,请关注后续文章。至此,监控linux主机java应用的内存使用告一段落。由于本人在技术方面的局限,文章不够全面也难免问题,请朋友们不吝赐教。