转自:http://blog.csdn.net/gzh0222/article/details/8538727java
一、为何会发生内存泄漏服务器
Java 如何检测内在泄漏呢?咱们须要一些工具进行检测,并发现内存泄漏问题,否则很容易发生down机问题。并发
编写java程序最为方便的地方就是咱们不须要管理内存的分配和释放,一切由jvm来进行处理,当java对象再也不被应用时,等到堆内存不够用时,jvm会进行垃圾回收,清除这些对象占用的堆内存空间,若是对象一直被应用,jvm没法对其进行回收,建立新的对象时,没法从Heap中获取足够的内存分配给对象,这时候就会致使内存溢出。而出现内存泄露的地方,通常是不断的往容器中存放对象,而容器没有相应的大小限制或清除机制。容易致使内存溢出。
当服务器应用占用了过多内存的时候,如何快速定位问题呢?如今,Eclipse MAT的出现使这个问题变得很是简单。EclipseMAT是著名的SAP公司贡献的一个工具,能够在Eclipse网站下载到它,彻底免费的。
要定位问题,首先你须要获取服务器jvm某刻内存快照。jdk自带的jmap能够获取内存某一时刻的快照,导出为dmp文件后,就能够用Eclipse MAT来分析了,找出是那个对象使用内存过多。jvm
二、内存泄漏的现象:工具
经常地,程序内存泄漏的最初迹象发生在出错以后,在你的程序中获得一个OutOfMemoryError。这种典型的状况发生在产品环境中,而在那里,你但愿内存泄漏尽量的少,调试的可能性也达到最小。也许你的测试环境和产品的系统环境不尽相同,致使泄露的只会在产品中暴露。这种状况下,你须要一个低负荷的工具来监听和寻找内存泄漏。同时,你还须要把这个工具同你的系统联系起来,而不须要从新启动他或者机械化你的代码。也许更重要的是,当你作分析的时候,你须要可以同工具分离而使得系统不会受到干扰。
一个OutOfMemoryError经常是内存泄漏的一个标志,有可能应用程序的确用了太多的内存;这个时候,你既不能增长JVM的堆的数量,也不能改变你的程序而使得他减小内存使用。可是,在大多数状况下,一个OutOfMemoryError是内存泄漏的标志。一个解决办法就是继续监听GC的活动,看看随时间的流逝,内存使用量是否会增长,若是有,程序中必定存在内存泄漏。性能
三、发现内存泄漏学习
1. jstat -gc pid测试
能够显示gc的信息,查看gc的次数,及时间。网站
其中最后五项,分别是young gc的次数,young gc的时间,full gc的次数,full gc的时间,gc的总时间。spa
2.jstat -gccapacity pid
能够显示,VM内存中三代(young,old,perm)对象的使用和占用大小,
如:PGCMN显示的是最小perm的内存使用量,PGCMX显示的是perm的内存最大使用量,
PGC是当前新生成的perm内存占用量,PC是但前perm内存占用量。
其余的能够根据这个类推, OC是old内纯的占用量。
3.jstat -gcutil pid
统计gc信息统计。
4.jstat -gcnew pid
年轻代对象的信息。
5.jstat -gcnewcapacity pid
年轻代对象的信息及其占用量。
6.jstat -gcold pid
old代对象的信息。
7.stat -gcoldcapacity pid
old代对象的信息及其占用量。
8.jstat -gcpermcapacity pid
perm对象的信息及其占用量。
9.jstat -class pid
显示加载class的数量,及所占空间等信息。
10.jstat -compiler pid
显示VM实时编译的数量等信息。
11.stat -printcompilation pid
当前VM执行的信息。
一些术语的中文解释:
S0C:年轻代中第一个survivor(幸存区)的容量 (字节)
S1C:年轻代中第二个survivor(幸存区)的容量 (字节)
S0U:年轻代中第一个survivor(幸存区)目前已使用空间 (字节)
S1U:年轻代中第二个survivor(幸存区)目前已使用空间 (字节)
EC:年轻代中Eden(伊甸园)的容量 (字节)
EU:年轻代中Eden(伊甸园)目前已使用空间 (字节)
OC:Old代的容量 (字节)
OU:Old代目前已使用空间 (字节)
PC:Perm(持久代)的容量 (字节)
PU:Perm(持久代)目前已使用空间 (字节)
YGC:从应用程序启动到采样时年轻代中gc次数
YGCT:从应用程序启动到采样时年轻代中gc所用时间(s)
FGC:从应用程序启动到采样时old代(全gc)gc次数
FGCT:从应用程序启动到采样时old代(全gc)gc所用时间(s)
GCT:从应用程序启动到采样时gc用的总时间(s)
NGCMN:年轻代(young)中初始化(最小)的大小 (字节)
NGCMX:年轻代(young)的最大容量 (字节)
NGC:年轻代(young)中当前的容量 (字节)
OGCMN:old代中初始化(最小)的大小 (字节)
OGCMX:old代的最大容量 (字节)
OGC:old代当前新生成的容量 (字节)
PGCMN:perm代中初始化(最小)的大小 (字节)
PGCMX:perm代的最大容量 (字节)
PGC:perm代当前新生成的容量 (字节)
S0:年轻代中第一个survivor(幸存区)已使用的占当前容量百分比
S1:年轻代中第二个survivor(幸存区)已使用的占当前容量百分比
E:年轻代中Eden(伊甸园)已使用的占当前容量百分比
O:old代已使用的占当前容量百分比
P:perm代已使用的占当前容量百分比
S0CMX:年轻代中第一个survivor(幸存区)的最大容量 (字节)
S1CMX :年轻代中第二个survivor(幸存区)的最大容量 (字节)
ECMX:年轻代中Eden(伊甸园)的最大容量 (字节)
DSS:当前须要survivor(幸存区)的容量 (字节)(Eden区已满)
TT:持有次数限制
MTT :最大持有次数限制
若是定位内存泄漏问题我通常使用以下命令:
Jstat -gcutil15469 2500 70
[root@ssss logs]# jstat -gcutil 15469 1000 300
S0 S1 E O P YGC YGCT FGC FGCT GCT
0.00 1.46 26.54 4.61 30.14 35 0.872 0 0.000 0.872
0.00 1.46 46.54 4.61 30.14 35 0.872 0 0.000 0.872
0.00 1.46 47.04 4.61 30.14 35 0.872 0 0.000 0.872
0.00 1.46 65.19 4.61 30.14 35 0.872 0 0.000 0.872
0.00 1.46 67.54 4.61 30.14 35 0.872 0 0.000 0.872
0.00 1.46 87.54 4.61 30.14 35 0.872 0 0.000 0.872
0.00 1.46 88.03 4.61 30.14 35 0.872 0 0.000 0.872
1.48 0.00 5.56 4.62 30.14 36 0.874 0 0.000 0.874
1000 表明多久间隔显示一次,
100 表明显示一次。
S0 — Heap上的 Survivor space 0 区已使用空间的百分比
S1 — Heap上的 Survivor space 1 区已使用空间的百分比
E — Heap上的 Eden space 区已使用空间的百分比
O — Heap上的 Old space 区已使用空间的百分比
P — Perm space 区已使用空间的百分比
YGC — 从应用程序启动到采样时发生 Young GC 的次数
YGCT– 从应用程序启动到采样时 Young GC 所用的时间(单位秒)
FGC — 从应用程序启动到采样时发生 Full GC 的次数
FGCT– 从应用程序启动到采样时 Full GC 所用的时间(单位秒)
GCT — 从应用程序启动到采样时用于垃圾回收的总时间(单位秒)
若是有大量的FGC就要查询是否有内存泄漏的问题了,图中的FGC数量就比较大,而且执行时间较长,这样就会致使系统的响应时间较长,若是对jvm的内存设置较大,那么执行一次FGC的时间可能会更长。
若是为了更好的证实FGC对服务器性能的影响,咱们可使用java visualVM来查看一下:
从上图能够发现执行FGC的状况,下午3:10分以前是没有FGC的,以后出现大量的FGC。
上图是jvm堆内存的使用状况,下午3:10分以前的内存回收仍是比较合理,可是以后大量内存没法回收,最后致使内存愈来愈少,致使大量的full gc。
下面咱们在看看大量full GC对服务器性能的影响,下面是我用loadrunner对咱们项目进行压力测试相应时间的截图:
从图中能够发现有,在进行full GC后系统的相应时间有了明显的增长,点击率和吞吐量也有了明显的降低。因此java内存泄漏对系统性能的影响是不可忽视的。
三、定位内存泄漏
固然经过上面几种方法咱们能够发现java的内存泄漏问题,可是做为一名合格的高级工程师,确定不甘心就把这样的结论交给开发,固然这也的结论交给开发,开发也很难定位问题,为了更好的提供本身在公司的地位,咱们必须给开发工程师提供更深刻的测试结论,下面就来认识一下MemoryAnalyzer.exe。java内存泄漏检查工具利器。
首先咱们必须对jvm的堆内存进行dump,只有拿到这个文件咱们才能分析出jvm堆内存中到底存了些什么内容,到底在作什么?
MemoryAnalyzer的用户我在这里就不一一说明了,个人博客里也有说明,下面就展现我测试的成功图:
其中深蓝色的部分就为内存泄漏的部分,java的堆内存一共只有481.5M而内存泄漏的部分独自占有了336.2M因此本次的内存泄漏很明显,那么我就来看看那个方法致使的内存泄漏:
从上图咱们能够发现红线圈着的方法占用了堆内存的67.75%,若是能把这个测试结果交给开发,开发是否是应该很好定位呢。因此做为一名高级测试工程师,咱们须要学习的东西太多。
虽然不肯定必定是内存泄漏,可是能够准确的告诉开发问题出现的缘由,有必定的说服力。