如何排查Java内存泄露排查

86人已关注
做一只愉快的码农Java开发人员都知道,Java利用垃圾回收机制来自动保持应用程序内存的干净和健康。然而可能有人不知道的是,即使使用了垃圾回收机制,Java中仍然可能存在内存泄漏风险。如果你碰到下面的错误代码:.lang.OutOfMemoryError: 如果你确认是内存分配不足,那么可以通过以下代码为应用程序增加可用内存:java -Xmsheapsize& -Xmxheapsize&不过对于内存泄漏来说这么做是治标不治本,只能起到缓解作用。内存泄漏的识别在将程序部署到生产环境之前检查一下是否存在内存泄漏的问题是很有必要的。这里可以通过垃圾收集器的指标来进行初步的判断。如GC后内存使用仍然持续上升,那么就可能有内存泄漏的问题,比如上面的这幅图,代码可以查看GitHub()。不过在现实中内存像图上一样线性增加的可能性是很小的,见图Old Gen,而GC suspension times或者Eden Space和Survivor空间使用并不足以识别出内存泄漏。缩小问题的范围要找出内存泄漏的原因当下已经有许多工具可用,比如JVisualVM或者jStat。这些工具是JDK自带的,所以大家随时都能用。除了要识别一些常用的内部Java类,一些用户自定义累同样需要识别。性能优化在日常的开发过程中,只要GC没有影响到性能,开发者就不会去关注内存设置于配置。从而埋下了潜在的隐患:因为内存问题并不只有溢出和泄露,GC时间过长同样会造成这个问题。比如下图中GC占用了16%的CPU。Heap设置Heap太小会导致频繁的GC,从而情景不难想象:增加GC会消耗更多的CPU,同时在GC时JVM会被冻结,最后导致一个很差的性能。总的来说,Heap太小的话,虽然GC时间变短,但是会变得更加频繁。Heap太大会导致GC时间边长。GC不会经常发生,但是一旦被触发,那么VM会被冻结很久。因此,如果这种情况下发生内存泄露,在最终JVM因为内存溢出崩溃之前,GC会非常频繁或者时间特别长。GC版本从Java 6开始,GC就改变了很多。Java 7引入了G1GC作为CMS GC的替代选择,而在Java 9中G1GC已成为默认选择。Java 8中移除了PermGen Space,之前存储在PermGen Space中的数据则改为存储在本地内存或者栈中。Java开发人员都知道,Java利用垃圾回收机制来自动保持应用程序内存的干净和健康。然而可能有人不知道的是,即使使用了垃圾回收机制,Java中仍然可能存在内存泄漏风险。如果你碰到下面的错误代码:.lang.OutOfMemoryError: 如果你确认是内存分配不足,那么可以通过以下代码为应用程序增加可用内存:java -Xmsheapsize& -Xmxheapsize&不过对于内存泄漏来说这么做是治标不治本,只能起到缓解作用。内存泄漏的识别在将程序部署到生产环境之前检查一下是否存在内存泄漏的问题是很有必要的。这里可以通过垃圾收集器的指标来进行初步的判断。如GC后内存使用仍然持续上升,那么就可能有内存泄漏的问题,比如上面的这幅图,代码可以查看GitHub()。不过在现实中内存像图上一样线性增加的可能性是很小的,见图Old Gen,而GC suspension times或者Eden Space和Survivor空间使用并不足以识别出内存泄漏。缩小问题的范围要找出内存泄漏的原因当下已经有许多工具可用,比如JVisualVM或者jStat。这些工具是JDK自带的,所以大家随时都能用。除了要识别一些常用的内部Java类,一些用户自定义累同样需要识别。性能优化在日常的开发过程中,只要GC没有影响到性能,开发者就不会去关注内存设置于配置。从而埋下了潜在的隐患:因为内存问题并不只有溢出和泄露,GC时间过长同样会造成这个问题。比如下图中GC占用了16%的CPU。Heap设置Heap太小会导致频繁的GC,从而情景不难想象:增加GC会消耗更多的CPU,同时在GC时JVM会被冻结,最后导致一个很差的性能。总的来说,Heap太小的话,虽然GC时间变短,但是会变得更加频繁。Heap太大会导致GC时间边长。GC不会经常发生,但是一旦被触发,那么VM会被冻结很久。因此,如果这种情况下发生内存泄露,在最终JVM因为内存溢出崩溃之前,GC会非常频繁或者时间特别长。GC版本从Java 6开始,GC就改变了很多。Java 7引入了G1GC作为CMS GC的替代选择,而在Java 9中G1GC已成为默认选择。Java 8中移除了PermGen Space,之前存储在PermGen Space中的数据则改为存储在本地内存或者栈中。
1、内存泄漏的现象:常常地,程序内存泄漏的最初迹象发生在出错之后,在程序中得到一个OutOfMemoryError。这种典型的情况发生在产品环境中,而在那里,希望内存泄漏尽可能的少,调试的可能性也达到最小。也许测试环境和产品的系统环境不尽相同,导致泄露的只会在产品中暴露。这种情况下,需要一个低负荷的工具来监听和寻找内存泄漏。同时,还需要把这个工具同系统联系起来,而不需要重新启动他或者机械化代码。也许更重要的是,当做分析的时候,需要能够同工具分离而使得系统不会受到干扰。一个OutOfMemoryError常常是内存泄漏的一个标志,有可能应用程序的确用了太多的内存;这个时候,既不能增加JVM的堆的数量,也不能改变程序而使得减少内存使用。但是,在大多数情况下,一个OutOfMemoryError是内存泄漏的标志。一个解决办法就是继续监听GC的活动,看看随时间的流逝,内存使用量是否会增加,如果有,程序中一定存在内存泄漏。2. 发现内存泄漏1. jstat -gc pid可以显示gc的信息,查看gc的次数,及时间。其中最后五项,分别是young gc的次数,young gc的时间,full gc的次数,full gc的时间,gc的总时间。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 pidold代对象的信息。7.stat -gcoldcapacity pidold代对象的信息及其占用量。8.jstat -gcpermcapacity pidperm对象的信息及其占用量。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 :最大持有次数限制1、内存泄漏的现象:常常地,程序内存泄漏的最初迹象发生在出错之后,在程序中得到一个OutOfMemoryError。这种典型的情况发生在产品环境中,而在那里,希望内存泄漏尽可能的少,调试的可能性也达到最小。也许测试环境和产品的系统环境不尽相同,导致泄露的只会在产品中暴露。这种情况下,需要一个低负荷的工具来监听和寻找内存泄漏。同时,还需要把这个工具同系统联系起来,而不需要重新启动他或者机械化代码。也许更重要的是,当做分析的时候,需要能够同工具分离而使得系统不会受到干扰。一个OutOfMemoryError常常是内存泄漏的一个标志,有可能应用程序的确用了太多的内存;这个时候,既不能增加JVM的堆的数量,也不能改变程序而使得减少内存使用。但是,在大多数情况下,一个OutOfMemoryError是内存泄漏的标志。一个解决办法就是继续监听GC的活动,看看随时间的流逝,内存使用量是否会增加,如果有,程序中一定存在内存泄漏。2. 发现内存泄漏1. jstat -gc pid可以显示gc的信息,查看gc的次数,及时间。其中最后五项,分别是young gc的次数,young gc的时间,full gc的次数,full gc的时间,gc的总时间。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 pidold代对象的信息。7.stat -gcoldcapacity pidold代对象的信息及其占用量。8.jstat -gcpermcapacity pidperm对象的信息及其占用量。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 :最大持有次数限制
当我们正在为生活疲于奔命时,生活已离我们而去。首先你要知道什么是内存泄漏。在c和c++的程序里内存泄漏指的是这样的内存块:在堆中还没有被释放也没有指针指向其地址的内存块。也就是你申请了一段内存,结果你把控制这块内存的遥控器丢了。java由于其垃圾回收的机制,这种定义下的内存泄漏是肯定不会有的。java的内存泄漏一般指的是有段内存你不用了,但是你一直留着指向它的指针。如果这样的东西非常多,最后你的内存就会不够了。因为这种情况下的内存是不会被回收的。不过,个人觉得这种情况根本不算真正意义的内存泄漏,因为你一直有着这段内存的控制权。首先你要知道什么是内存泄漏。在c和c++的程序里内存泄漏指的是这样的内存块:在堆中还没有被释放也没有指针指向其地址的内存块。也就是你申请了一段内存,结果你把控制这块内存的遥控器丢了。java由于其垃圾回收的机制,这种定义下的内存泄漏是肯定不会有的。java的内存泄漏一般指的是有段内存你不用了,但是你一直留着指向它的指针。如果这样的东西非常多,最后你的内存就会不够了。因为这种情况下的内存是不会被回收的。不过,个人觉得这种情况根本不算真正意义的内存泄漏,因为你一直有着这段内存的控制权。Java肯定会出现内存泄露的情况,比如打开了数据库连接,而且执行SQL语句出现了异常,但是没关闭数据库连接,这时候,底层的数据库连接的资源不会不释放,就出现了内存泄露了。&Java肯定会出现内存泄露的情况,比如打开了数据库连接,而且执行SQL语句出现了异常,但是没关闭数据库连接,这时候,底层的数据库连接的资源不会不释放,就出现了内存泄露了。&
东北大学(中国)
就是喜欢表情包~╭(╯^╰)╮Java一般情况下是不会有内存泄漏的,暂时没有被释放的无引用对象,也就是垃圾,我认为不算内存泄漏。关于Java内存泄漏,可参阅Java一般情况下是不会有内存泄漏的,暂时没有被释放的无引用对象,也就是垃圾,我认为不算内存泄漏。关于Java内存泄漏,可参阅一般来说内存泄漏有两种情况。一种情况,在堆中的分配的内存,在没有将其释放掉的时候,就将所有能访问这块内存的方式都删掉(如指针重新赋值);另一种情况则是在内存对象明明已经不需要的时候,还仍然保留着这块内存和它的访问方式(引用)。第一种情况,在Java中已经由于垃圾回收机制的引入,得到了很好的解决。所以,Java中的内存泄漏,主要指的是第二种情况。可能光说概念太抽象了,大家可以看一下这样的例子:1 Vector v=new Vector(10);2 for (int i=1;i&100; i++){3 Object o=new Object();4 v.add(o);5 o=6 }在这个例子中,代码栈中存在Vector对象的引用v和Object对象的引用o。在For循环中,我们不断的生成新的对象,然后将其添加到Vector对象中,之后将o引用置空。问题是当o引用被置空后,如果发生GC,我们创建的Object对象是否能够被GC回收呢?答案是否定的。因为,GC在跟踪代码栈中的引用时,会发现v引用,而继续往下跟踪,就会发现v引用指向的内存空间中又存在指向Object对象的引用。也就是说尽管o引用已经被置空,但是Object对象仍然存在其他的引用,是可以被访问到的,所以GC无法将其释放掉。如果在此循环之后,Object对象对程序已经没有任何作用,那么我们就认为此Java程序发生了内存泄漏。尽管对于C/C++中的内存泄露情况来说,Java内存泄露导致的破坏性小,除了少数情况会出现程序崩溃的情况外,大多数情况下程序仍然能正常运行。但是,在移动设备对于内存和CPU都有较严格的限制的情况下,Java的内存溢出会导致程序效率低下、占用大量不需要的内存等问题。这将导致整个机器性能变差,严重的也会引起抛出OutOfMemoryError,导致程序崩溃。一般来说内存泄漏有两种情况。一种情况,在堆中的分配的内存,在没有将其释放掉的时候,就将所有能访问这块内存的方式都删掉(如指针重新赋值);另一种情况则是在内存对象明明已经不需要的时候,还仍然保留着这块内存和它的访问方式(引用)。第一种情况,在Java中已经由于垃圾回收机制的引入,得到了很好的解决。所以,Java中的内存泄漏,主要指的是第二种情况。可能光说概念太抽象了,大家可以看一下这样的例子:1 Vector v=new Vector(10);2 for (int i=1;i&100; i++){3 Object o=new Object();4 v.add(o);5 o=6 }在这个例子中,代码栈中存在Vector对象的引用v和Object对象的引用o。在For循环中,我们不断的生成新的对象,然后将其添加到Vector对象中,之后将o引用置空。问题是当o引用被置空后,如果发生GC,我们创建的Object对象是否能够被GC回收呢?答案是否定的。因为,GC在跟踪代码栈中的引用时,会发现v引用,而继续往下跟踪,就会发现v引用指向的内存空间中又存在指向Object对象的引用。也就是说尽管o引用已经被置空,但是Object对象仍然存在其他的引用,是可以被访问到的,所以GC无法将其释放掉。如果在此循环之后,Object对象对程序已经没有任何作用,那么我们就认为此Java程序发生了内存泄漏。尽管对于C/C++中的内存泄露情况来说,Java内存泄露导致的破坏性小,除了少数情况会出现程序崩溃的情况外,大多数情况下程序仍然能正常运行。但是,在移动设备对于内存和CPU都有较严格的限制的情况下,Java的内存溢出会导致程序效率低下、占用大量不需要的内存等问题。这将导致整个机器性能变差,严重的也会引起抛出OutOfMemoryError,导致程序崩溃。
安徽师范大学
1、关于内存泄露java虚拟机可以自动回收没有被引用的对象。但有时应用程序会有一些对象被引用了但不被使用。这样的对象越来越多的,而虚拟机不能自动回收,就会导致java程序使用的堆越来越多,当超过堆的限制时就会抛出OutOfMemory的错误。基本上如果抛出OutOfMemory有两种原因:1。内存泄露,2。应用程序本身就是需要这么多的内存。在启动java的时候加入-verbosegc(Jrockit是-verbose:memory或gc)参数。每次垃圾回收都会把回收信息打印到标准输出中。如果回收后的内存时候随时间不断增长。那么应用程序肯定是有内存泄露。确定是内存泄露后,就需要找到是那些对象占用了内存。这需要是使用工具进行检测。2、SUN JDK提供JDKPI和最新的JDKTI对内存泄露进行检测。JDKPI是sunjdk采用的一种可以检测堆大小情况的c语言的接口。但这个接口1.5中已经被废止。取而代之的是JDKTI3、试用内存泄露检测工具目的:找到一个可以对在Linux上启动虚拟机,进行监控的工具。并且是在生产环境下3.1、JProbeJProbe是Quest公司提供的工具。具有GUI界面(java写的界面)。可以显示每个类型占堆的大小。工具有几个缺点:1、只有通过JProbe启动的虚拟机,JProbe才能对其的堆进行检测。这就要求,虚拟机要和JProbe安装在一台机器上。但很多内存泄露是在生产环境中发现的。生产环境中的很多都是Linux机器,程序员通过ssh控制。要使用图形工具配置比较费劲。修正:应该可以象JRockit那样在服务器开通一个端口,在本地监控。但我没有仔细研究,应该和JProfiler差不多。2、并没有使用服务器的启动脚本。如果你在脚本里修改了classpath,加载了新的类,就无法对这个类进行测试了。也就是说,即时在测试环境中,无法做到与生产环境完全一致,那么测试结果也就没什么意义了。3.2
HPROFHPROF是sun内置的工具。启动虚拟机的时候,加入参数可以控制是否使用Hprof。Hprof可以列出堆中占用内存最多的对象。启动方式:在启动虚拟机的时候偶加入参数-Xrunhprof:head=site查看方式:threaddmup的时候会生成java.hprof.txt文件。里边记录了head的详细信息。这个工具的缺点是:加入hprof的参数后,java虚拟机的运行非常慢。据说要比正常慢20倍。无法应用在生产环境中。3.3
JRockitMission Console这个工具只能监控bea的虚拟机JRockit的运行情况,使用的接口也不是sunjdk的jvmpi或jvmti了。在JRockitMissionConsole1.4.2中是集成在JRockit中的(jrockit-R27.4.0-jdk14.2_15\bin\jrmc.exe)。基本的使用方法:在启动JRockit虚拟机时开放监控端口,JRockitMission Console可以在任何机器上运行,对开放了端口的虚拟机进行监控。并且基本没有额外的系统开销,与sunjdk完全兼容。这样就可以在生产环境中启动jdk,然后在程序员的机器中对Linux上的jdk的的运行情况进行监控。这正式我想要的。因为我们的服务器使用的是1.4.2。所以,首先下载JRockit1.4.2的最新版本。并且要最新的,因为JRockit版本号低于1.4.2.10的似乎不能使用JRockitMission Console中的Memory Leak Detector。JRockit1.4.2无论是在window还是Linux安装都非常方便,按bea的文档做就可以。然后重新配置一个weblogic的domain。配置的时候指定使用JRockit作为虚拟机。修改startWeblogi.sh脚本加入-Xmanagement:port=7090参数,最好也把-Xverbose:memory加上,可以看到垃圾回收的情况。启动weblogic。在本机启动JRockitMission Console,建立对服务器的连接,启动Memory Leak Detector就可以对java的堆进行监视了。Memory Leak Detector有4个视图:1、趋势:这视图里列出了所有类型,占堆的百分比,对象数,最重要的是“增长(字节/秒)”,这个列高了。就有可能是内存泄露。注意:这个视图在jdk进行垃圾回收后才传回信息,也就是说,如果没有进行垃圾回收就不会刷新。建议通过点垃圾回收按钮刷新界面。否则,虽然可以自动刷新,但增长这个列一直是0,不进行自动计算。也许是一个bug吧。2、类型:这个视图,通过在趋势中对感兴趣的类,右键-&显示引用类型来进入。主要显示了选中类,与引用选中类的类。用箭头显示中间的关系。非常漂亮。3、实例:这个视图显示的是类的实例。是在类型中对感兴趣的类型右键-&显示实例,或最大数组中右键-&显示实例切换到这个视图的。显示一些实例之间的引用关系。4、分配堆栈跟踪:这里可以看到指定类是在那个类中的第几行被实例化的。注意:只有切换到这个视图,才对指定的类进行跟踪。如果切换过来后,这个类没有被实例化过,那么也看不到任何调用信息。这是最有用的一个视图。类型和实例虽然很全,但由于类之间的关系复杂,有时,并不能找的找到需要的信息。这个工具的缺点是:使用Memory Leak Detector,需要到bea下载license。这个license分为2中。一种是开发用的,这种在jdk启动1小时后,Memory Leak Detector就失效了。必须重新启动虚拟机才行。另一种是企业级的,需要收费,没有时间限制。1、关于内存泄露java虚拟机可以自动回收没有被引用的对象。但有时应用程序会有一些对象被引用了但不被使用。这样的对象越来越多的,而虚拟机不能自动回收,就会导致java程序使用的堆越来越多,当超过堆的限制时就会抛出OutOfMemory的错误。基本上如果抛出OutOfMemory有两种原因:1。内存泄露,2。应用程序本身就是需要这么多的内存。在启动java的时候加入-verbosegc(Jrockit是-verbose:memory或gc)参数。每次垃圾回收都会把回收信息打印到标准输出中。如果回收后的内存时候随时间不断增长。那么应用程序肯定是有内存泄露。确定是内存泄露后,就需要找到是那些对象占用了内存。这需要是使用工具进行检测。2、SUN JDK提供JDKPI和最新的JDKTI对内存泄露进行检测。JDKPI是sunjdk采用的一种可以检测堆大小情况的c语言的接口。但这个接口1.5中已经被废止。取而代之的是JDKTI3、试用内存泄露检测工具目的:找到一个可以对在Linux上启动虚拟机,进行监控的工具。并且是在生产环境下3.1、JProbeJProbe是Quest公司提供的工具。具有GUI界面(java写的界面)。可以显示每个类型占堆的大小。工具有几个缺点:1、只有通过JProbe启动的虚拟机,JProbe才能对其的堆进行检测。这就要求,虚拟机要和JProbe安装在一台机器上。但很多内存泄露是在生产环境中发现的。生产环境中的很多都是Linux机器,程序员通过ssh控制。要使用图形工具配置比较费劲。修正:应该可以象JRockit那样在服务器开通一个端口,在本地监控。但我没有仔细研究,应该和JProfiler差不多。2、并没有使用服务器的启动脚本。如果你在脚本里修改了classpath,加载了新的类,就无法对这个类进行测试了。也就是说,即时在测试环境中,无法做到与生产环境完全一致,那么测试结果也就没什么意义了。3.2
HPROFHPROF是sun内置的工具。启动虚拟机的时候,加入参数可以控制是否使用Hprof。Hprof可以列出堆中占用内存最多的对象。启动方式:在启动虚拟机的时候偶加入参数-Xrunhprof:head=site查看方式:threaddmup的时候会生成java.hprof.txt文件。里边记录了head的详细信息。这个工具的缺点是:加入hprof的参数后,java虚拟机的运行非常慢。据说要比正常慢20倍。无法应用在生产环境中。3.3
JRockitMission Console这个工具只能监控bea的虚拟机JRockit的运行情况,使用的接口也不是sunjdk的jvmpi或jvmti了。在JRockitMissionConsole1.4.2中是集成在JRockit中的(jrockit-R27.4.0-jdk14.2_15\bin\jrmc.exe)。基本的使用方法:在启动JRockit虚拟机时开放监控端口,JRockitMission Console可以在任何机器上运行,对开放了端口的虚拟机进行监控。并且基本没有额外的系统开销,与sunjdk完全兼容。这样就可以在生产环境中启动jdk,然后在程序员的机器中对Linux上的jdk的的运行情况进行监控。这正式我想要的。因为我们的服务器使用的是1.4.2。所以,首先下载JRockit1.4.2的最新版本。并且要最新的,因为JRockit版本号低于1.4.2.10的似乎不能使用JRockitMission Console中的Memory Leak Detector。JRockit1.4.2无论是在window还是Linux安装都非常方便,按bea的文档做就可以。然后重新配置一个weblogic的domain。配置的时候指定使用JRockit作为虚拟机。修改startWeblogi.sh脚本加入-Xmanagement:port=7090参数,最好也把-Xverbose:memory加上,可以看到垃圾回收的情况。启动weblogic。在本机启动JRockitMission Console,建立对服务器的连接,启动Memory Leak Detector就可以对java的堆进行监视了。Memory Leak Detector有4个视图:1、趋势:这视图里列出了所有类型,占堆的百分比,对象数,最重要的是“增长(字节/秒)”,这个列高了。就有可能是内存泄露。注意:这个视图在jdk进行垃圾回收后才传回信息,也就是说,如果没有进行垃圾回收就不会刷新。建议通过点垃圾回收按钮刷新界面。否则,虽然可以自动刷新,但增长这个列一直是0,不进行自动计算。也许是一个bug吧。2、类型:这个视图,通过在趋势中对感兴趣的类,右键-&显示引用类型来进入。主要显示了选中类,与引用选中类的类。用箭头显示中间的关系。非常漂亮。3、实例:这个视图显示的是类的实例。是在类型中对感兴趣的类型右键-&显示实例,或最大数组中右键-&显示实例切换到这个视图的。显示一些实例之间的引用关系。4、分配堆栈跟踪:这里可以看到指定类是在那个类中的第几行被实例化的。注意:只有切换到这个视图,才对指定的类进行跟踪。如果切换过来后,这个类没有被实例化过,那么也看不到任何调用信息。这是最有用的一个视图。类型和实例虽然很全,但由于类之间的关系复杂,有时,并不能找的找到需要的信息。这个工具的缺点是:使用Memory Leak Detector,需要到bea下载license。这个license分为2中。一种是开发用的,这种在jdk启动1小时后,Memory Leak Detector就失效了。必须重新启动虚拟机才行。另一种是企业级的,需要收费,没有时间限制。大王叫我来巡山哪,我把砖来搬一搬内存泄露不是java的问题.是开发的问题. 其实看看虚拟机原理会有很大帮助.内存泄露不是java的问题.是开发的问题. 其实看看虚拟机原理会有很大帮助.
做温文尔雅的菇凉1. java的内存泄露一般是因为引用始终得不到回收造成的。2. java swing是自己绘制的UI,渲染比较慢,用swt可以调用本地操作系统的UI,速度就快的多了。1. java的内存泄露一般是因为引用始终得不到回收造成的。2. java swing是自己绘制的UI,渲染比较慢,用swt可以调用本地操作系统的UI,速度就快的多了。程序在本地运行一切正常,可是布署到远端就会出现内存无限制的增长,最后系统瘫痪。程序在本地运行一切正常,可是布署到远端就会出现内存无限制的增长,最后系统瘫痪。
后可以回答该问题
相关标签:
相关标签:
关注我们咨询服务合作法律法规京ICP备号
下载申请方APP
即刻拥有你的学业规划助手

我要回帖

更多关于 如何防止内存泄露 的文章

 

随机推荐