设为首页 收藏本站
查看: 1016|回复: 0

[经验分享] 用IBM HeapAnalyzer和MOD4J分析Java内存泄漏

[复制链接]

尚未签到

发表于 2015-10-3 12:09:31 | 显示全部楼层 |阅读模式
  内存泄漏是比较常见的一种应用程序性能问题,一旦发生,则系统的可用内存和性能持续下降;最终将导致内存不足(OutOfMemory),系统彻底宕掉,不能响应任何请求,其危害相当严重。同时,Java堆(Heap)中大量的对象以及对象间之复杂关系,导致内存泄漏问题的探测和分析均比较困难,采用相应的辅助工具是很必要的。
  我使用的比较多的是Memory Dump Diagnostic for Java (MDD4J)和IBM HeapAnalyzer,这两个工具都能支持几乎所有JDK版本所生成的堆转储文件,使用前可以在两者的帮助文件中查看一下支持列表。
  先说一下IBM HeapAnalyzer,下载之后首先阅读一下readme,这上面详细写了HeapAnalyzer的使用方法。对于我用的2.6版本(最新为3.8),可以在命令行中输入<Java path>java &#8211;Xmx[heapsize] &#8211;jar ha26.jar <heapdump file>来启动工具并加载heapdump文件。对于比较大的heapdump,将-Xmx设置一个较大的值(大于heapdump的大小),来避免加载过程中的OOM。对于64位机器上产生的超大heapdump,个人机器上分析就不大可能了。
  打开heapdump文件后,我一般点击&#8220;Analysis&#8221;里的&#8220;Tree View&#8221;,以树的形式从根节点展示内存对象分配的信息

  第一行java.lang.ref.Refenrence这个class及它的76个children占用了67%的已用堆大小(31M/46M),它本身仅占用了76bits。双击java.lang.ref.Refenrence,我们可以看到它所引用的两个子节点。其中一个子节点java.lang.ref.Finalizer后的67%指引我们内存泄漏的问题应该在它的引用上。

  
  接下去你可以逐级展开,或者右键点击&#8220;Locate a leak suspect&#8221;,让HeapAnalyzer帮你找到泄漏可能发生的地方。泄漏一般发生在那些拥有&#8220;超乎寻常多&#8221;的引用(子节点)的class上,正是这些创建后没有释放、累积了成千上百的对象,造成了OutOfMemory。右键中的&#8220;Go to the largest drop subtrees&#8221;也是以此为原理而设的,它的解释为:

  &#8220;Search for total size drop&#8221; will find a size drop between the total size of a parent and the biggest total size of child of the parent.
  因为出现泄漏的点,每个子节点占用的内存空间不大,但是巨大的数量会导致父节点占用的total size很大。不过反过来寻找到的点都是泄漏发生的地方这种说法是不成立的,否则也不需要我们来分析了。
  更多细节的内容,可以看这篇PPT
  Memory Dump Diagnostic for Java (MDD4J)则是IBM Support Assistant(ISA)里的一个工具,可以在ISA里加载。它的使用方法和HeapAnalyzer类似,不过它会自动列出&#8220;可疑泄漏点&#8221;供分析。所依据的,是&#8220;分析算法查找父对象与子对象之间对象大小的显著变化。这些发生显著变化的父对象可能是基于数组的容器对象,它们包含大量不断增大的子对象。&#8221;
  具体的使用方法可以参考《WebSphere Application Server 中的内存泄漏检测与分析:第 2 部分:用于泄漏检测与分析的工具和功能》一文中的实际案例。(不过文中的版本应该比较低,现在能下到的2和3版本有些不同,不过不妨碍使用).
  Heapdump工具的使用很简单,难点在于找到&#8220;内存泄漏的真正原因&#8221;,一般需要通过多个heapdump文件的对比才能找到

  比较分析用于对运行内存泄漏应用程序期间(即可用 Java 堆内存流失时)获取的两个内存转储进行分析。在运行泄漏应用程序的早期触发的内存转储被称为基线内存转储,发生泄漏的应用程序运行一段时间(以允许泄漏程度加大)后触发的内存转储被称为主内存转储。在发生了内存泄漏的情况下,主内存转储可能包含大量对象,而这些对象占用的 Java 堆空间量会比基线内存转储大很多。
  为了获得更好的分析结果,建议使主内存转储的触发点与基线内存转储的触发点在时间上拉开一定距离,从而使总耗用堆大小在两个触发点之间大幅增长。
  如果发现&#8220;主内存转储&#8221;中的某个对象数量大大大于&#8220;基线内存转储&#8221;,那么这个对象一般就是发生泄漏的点。但是要避免在appserver刚启动时就做heapdump,否则会把正常需要分配的对象当作泄漏嫌疑点。比如原先运行3天会发生OOM,那么可以:缩小堆大小,让OOM提早发生;在运行4个小时后每隔4小时手动做一次Heapdump直到OOM发生。这些动作也许不适合在生产环境下进行,可以另建测试环境进行。
  之前几篇文章中介绍的分析gc log,和本文讲到的分析heapdump,都是脱机分析法。它们的缺陷就是无法找到代码引起的&#8220;性能低下&#8221;的原因,正如《用HPjtune分析GC日志》里所看到的那样,系统性能很差,但是没有OOM发生,可用堆在每次full gc后还不断减少的现象不能简单怪罪为内存泄漏,毕竟最后都回收下来了,如果手动做heapdump,可能有问题的对象已被回收,无法得到正确的结果。这种情况下要使用诸如Jprofile这样直接附加到JVM上的工具来监测了。
  最后附一下手动生成heapdump的方法,免得事到临头在google。
  在Linux/AIX环境下
  使用Kill -3 pid命令来调用堆转储.
  Windows环境下

  1. 找到JVM对象名字。
<wsadmin> set objectName [$AdminControl queryNames
WebSphere:type=JVM,process=<servername>,node=<nodename>,*]
  2. 对JVM MBean调用generateHeapDump操作。
<wsadmin> $AdminControl invoke $objectName generateHeapDump
  如果上述方法是没有生成,那么进行下面的设置。

访问管理控制台
转到&#8220;服务器&#8221;>&#8220;应用程序服务器&#8221;> Server1(或者要获取其堆转储的服务器的名称)>&#8220;进程定义&#8221;>&#8220;环境条目&#8221;。
单击&#8220;新建&#8221;。
在&#8220;名称&#8221;字段中,输入 IBM_HEAPDUMP(默认是开启的)。在&#8220;值&#8221;字段中,输入 true。
单击&#8220;确定&#8221;。
重复步骤 3 至 5,但将 IBM_HEAPDUMP_OUTOFMEMORY 设置为 true。
缺省情况下,将在 ~/WebSphere/AppServer/ 目录中创建内存转储(对于 WebSphere Application Server V6.x 而言,缺省目录是:~/WebSphere/AppServer/profiles/default)。要将堆转储目标定向到另一个目录,请转至&#8220;环境条目&#8221;,单击&#8220;新建&#8221;,将 IBM_HEAPDUMPDIR 设置为适当的目录(例如 /heapdumps),然后单击&#8220;确定&#8221;。
单击&#8220;保存&#8221;,然后在下一个屏幕中再次单击&#8220;保存&#8221;。
转到&#8220;服务器&#8221;>&#8220;应用程序服务器&#8221;> server1(或者要获取其堆转储的服务器的名称)>&#8220;进程定义&#8221;>&#8220;Java 虚拟机&#8221;。
选择&#8220;详细垃圾回收&#8221;。
单击&#8220;保存&#8221;,然后在下一个屏幕中再次单击&#8220;保存&#8221;。
重新启动服务器。
打开命令提示符并转至 /WebSphere/AppServer/bin 目录。
通过发出 kill -3 XXXXX 命令来调用堆转储,其中 XXXXX 是进程标识。
  如果WebSphere运行在HP-UX上,那么需要


  • 访问管理控制台
  • 转到&#8220;服务器&#8221;>&#8220;应用程序服务器&#8221;> Server1(或者要获取其堆转储的服务器的名称)>&#8220;进程定义&#8221;>&#8220;环境条目&#8221;。
  • 在&#8220;常规参数&#8221;中,输入:-Xrunhprof:depth=0,heap=dump,format=a,thread=n,doe=n
  • 缺省情况下,将在 ~/Websphere/AppServer/ 目录中创建内存转储。要将堆转储目标定向到另一个目录,请添加 HProf 参数 file=/heapdumpdir/hprof.txt,其中 heapdumpdir 是适当的目录,而 hprof.txt 是适当的文件名。如果创建了多个内存转储,那么将把每个内存转储追加到同一个 hprof.txt 文件中。
  • 选中&#8220;启用详细垃圾回收方式&#8221;。
  • 重新启动服务器。
  • 通过发出 kill -3 XXXXX 命令创建堆转储,其中 XXXXX 是进程标识。
  • 除非另有指定,否则将在 ~/WebSphere/AppServer/ 目录中创建 hprof 转储,并且文件名看起来类似于 java.hprof.txt。
  • 关闭应用程序服务器,然后移动 hprof 转储文件。直到正确关闭应用程序服务器之后,hprof 转储文件才完整。
  • 注意:请检查是否每个 hprof 转储都包含 HEAP DUMP BEGIN 和 HEAP DUMP END 这两组标记。如果 hprof 转储的这两组标记不齐全,那么表明该转储不完整且不能用于分析。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-122100-1-1.html 上篇帖子: IBM知识库收藏 下篇帖子: IBM Cognos BI 最佳实践: 定制 IBM Cognos 8 UI
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表