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差不多。见:http://hi.baidu.com/shiliangshuai/blog/item/65d76263f0850c640d33fae0.html 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,没有改进就没有必要推出了。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值