Java内存泄漏原因、判定及解决方法

发表于:2009-4-15 10:03

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:未知    来源:网络转载

#
java

  引子

  公司有一个项目,已经交付客户使用最近总出现heap被占满。程序没有相应的情况。公司让我查一查,正好我也早想研究一下java内存泄漏的问题。

  目录:

  1 关于内存泄露

  2 SUN JDK提供 JDKPI和最新的JDKTI对内存泄露进行检测。

  3 试用内存泄露检测工具

  3.1 JProbe

  3.2 HPROF

  3.3 JRockit Mission Console

  正文

  1 关于内存泄露

  java虚拟机可以自动回收没有被引用的对象。但有时应用程序会有一些对象被引用了但不被使用。这样的对象越来越多的,而虚拟机不能自动回收,就会导致java程序使用的堆越来越多,当超过堆的限制时就会抛出OutOfMemory的错误。

  基本上如果抛出OutOfMemory有两种原因:1。内存泄露,2。应用程序本身就是需要这么多的内存。

  在启动java的时候加入 -verbosegc(Jrockit是-verbose:memory或gc)参数。每次垃圾回收都会把回收信息打印到标准输出中。如果回收后的内存时候随时间不断增长。那么应用程序肯定是有内存泄露。

  确定是内存泄露后,就需要找到是那些对象占用了内存。这需要是使用工具进行检测。

  2 SUN JDK提供 JDKPI和最新的JDKTI对内存泄露进行检测。

  JDKPI是sun jdk采用的一种可以检测堆大小情况的c语言的接口。但这个接口1.5中已经被废止。

  取而代之的是JDKTI

  3 试用内存泄露检测工具

  目的:找到一个可以对在Linux上启动虚拟机,进行监控的工具。并且是在生产环境下

  3.1 JProbe

  JProbe是Quest公司提供的工具。具有GUI界面(java写的界面)。可以显示每个类型占堆的大小。

  工具有几个缺点:

  1、只有通过JProbe启动的虚拟机,JProbe才能对其的堆进行检测。这就要求,虚拟机要和JProbe安装在一台机器上。但很多内存泄露是在生产环境中发现的。生产环境中的很多都是Linux机器,程序员通过ssh控制。要使用图形工具配置比较费劲。修正:应该可以象JRockit那样在服务器开通一个端口,在本地监控。但我没有仔细研究,应该和JProfiler差不多。

  2、并没有使用服务器的启动脚本。如果你在脚本里修改了classpath,加载了新的类,就无法对这个类进行测试了。也就是说,即时在测试环境中,无法做到与生产环境完全一致,那么测试结果也就没什么意义了。

  3.2 HPROF

  HPROF是sun内置的工具。启动虚拟机的时候,加入参数可以控制是否使用Hprof。Hprof可以列出堆中占用内存最多的对象。

  启动方式:在启动虚拟机的时候偶加入参数-Xrunhprof:head=site

  查看方式:thread dmup的时候会生成java.hprof.txt文件。里边记录了head的详细信息。

  这个工具的缺点是:

  加入hprof的参数后,java虚拟机的运行非常慢。

  据说要比正常慢20倍。无法应用在生产环境中。

  3.3 JRockit Mission Console

  这个工具只能监控bea的虚拟机JRockit的运行情况,使用的接口也不是sun jdk的jvmpi或jvmti了。

  在JRockitMissionConsole1.4.2中是集成在JRockit中的(jrockit-R27.4.0-jdk1.4.2_15\bin\jrmc.exe)。

  基本的使用方法:在启动JRockit虚拟机时开放监控端口,JRockit Mission Console可以在任何机器上运行,对开放了端口的虚拟机进行监控。并且基本没有额外的系统开销,与sun jdk完全兼容。这样就可以在生产环境中启动jdk,然后在程序员的机器中对Linux上的jdk的的运行情况进行监控。这正式我想要的。

  因为我们的服务器使用的是1.4.2。所以,首先下载JRockit 1.4.2的最新版本。并且要最新的,因为JRockit版本号低于1.4.2.10的似乎不能使用JRockit Mission Console 中的Memory Leak Detector。

  JRockit 1.4.2 无论是在window还是Linux安装都非常方便,按bea的文档做就可以。

  然后重新配置一个weblogic的domain。配置的时候指定使用JRockit作为虚拟机。

  修改startWeblogi.sh脚本加入-Xmanagement:port=7090参数,最好也把-Xverbose:memory加上,可以看到垃圾回收的情况。启动weblogic。

  在本机启动JRockit Mission 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就失效了。必须重新启动虚拟机才行。

  另一种是企业级的,需要收费,没有时间限制。

  限于时间的关系就写这么粗糙吧。

  参考资料:

  非常多。说实话,我也记不住了。

  后记:

  由于没有找到破解的license,所以只好通过增加java堆栈的大小来延缓程序的死掉。其实,如果设置为512程序基本上可以挺一个月。我给设置了1G。2个月应该能挺住。

  同事我在启动的时候加入了-verbosegc参数。希望能打印出一些有用的gc信息。

  在设置堆栈的过程中发现一个问题。刚刚启动的时候,sun 的jdk 大概使用了30M的内存。而JRockit则使用了300M。JRockit本身也有点问题。观察观察再说吧。

  以后有时间再试用一下sun jdk 1.5和1.6在这方面应该有很大的改进。毕竟新推出了JVMTI来取代JVMPI,没有改进就没有必要推出了。

《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号