`
RednaxelaFX
  • 浏览: 3016015 次
  • 性别: Icon_minigender_1
  • 来自: 海外
社区版块
存档分类
最新评论

通过JMX控制在full GC前后做heap dump

阅读更多
后一篇:通过jinfo工具在full GC前后做heap dump

有时候我们想知道一个Java程序在一次full GC的时候到底回收了哪些对象。特别是当full GC看起来很频密但系统看起来却又没有内存泄漏的时候,了解究竟是哪些对象引致了这些GC会对调优有帮助。

做了个简单的例子,讲解一种简单的办法在full GC的前后得到heap dump。本文说的办法只能在HotSpot VM上使用;其它JVM要达到同样的目的或许有其它做法,回头有机会再说。
(同样的工作在JRockit或者J9上做似乎都更容易些…

======================================================================

一般获取heap dump的办法

1、jmap
大家最熟悉的办法或许就是JDK自带的命令行工具jmap了。jmap可以在任何时候连接到一个跑在HotSpot VM的Java进程上,根据需要制作HPROF格式的heap dump。
jmap -dump:format=b,file=<filename> <pid>

这是最常用的用法。

在Sun的JDK 5和JDK 1.4.2的后期版本中(JDK 5 update 17和JDK 1.4.2 update 16或更高版本),还可以在启动参数里加上-XX:+HeapDumpOnCtrlBreak,然后通过ctrl + break或者发生SIGQUIT来让VM生成heap dump。
不过这个参数在Sun JDK 6里不存在;JDK6上直接用jmap更方便些,倒也没关系。
JRockit R28倒是支持使用这个参数。

2、JConsoleVisualVMMAT
这几个工具都封装了heap dump的功能,用起来很方便——只要知道如何让这些工具连接到目标进程上。所以它们通常在本地使用很方便,而要连接远程进程就麻烦一些。
还有别的一些工具也有提供生成heap dump功能的,不过我一下想不起来了就只写了上面仨。
GCMV或许也可以吧…呃,刚看了下,不行。还是得在VM里配置参数来生成heap dump。

JConsole:


VisualVM:



Eclipse Memory Analyzer (MAT):


3、JMX的API
Sun JDK通过JMX暴露出HotSpotDiagnosticMXBean,可以用于获取VM信息。它支持dumpHeap(String outputFile, boolean live)操作,让Java程序能直接指定路径和是否只要活对象进行heap dump。使用方法可以参考下面的链接:A. Sundararajan's Weblog: Programmatically dumping heap from Java applications

通过Serviceability Agent API也可以做heap dump。事实上jmap的其中一个模式就是包装了SA API的sun.jvm.hotspot.tools.HeapDumper来完成功能的。

4、JVMTI
很老的版本的JVMTI API里曾经有过heap dump函数,不过后来被去掉了

5、让JVM在一些特定事件发生的时候自动做heap dump
(这就是HotSpot操作起来没有JRockit和J9方便的地方了…)
有时候我们只想在发生OutOfMemoryError的时候让JVM自动生成一个heap dump出来,以便做事后分析。这种时候设置启动参数-XX:+HeapDumpOnOutOfMemoryError即可。参考下面的文章来了解该参数的一些历史:
Alan Bateman: Heap dumps are back with a vengeance!

HotSpot VM支持其它事件触发heap dump么?参考官方文档
引用
Flags marked as manageable are dynamically writeable through the JDK management interface (com.sun.management.HotSpotDiagnosticMXBean API) and also through JConsole. In Monitoring and Managing Java SE 6 Platform Applications, Figure 3 shows an example. The manageable flags can also be set through jinfo -flag.

声明为manageable的参数可以在运行时通过JMX修改。与heap dump相关的有以下4个参数:
hotspot/src/share/vm/runtime/globals.hpp
manageable(bool, HeapDumpBeforeFullGC, false,                             \
        "Dump heap to file before any major stop-world GC")               \
                                                                          \
manageable(bool, HeapDumpAfterFullGC, false,                              \
        "Dump heap to file after any major stop-world GC")                \
                                                                          \
manageable(bool, HeapDumpOnOutOfMemoryError, false,                       \
        "Dump heap to file when java.lang.OutOfMemoryError is thrown")    \
                                                                          \
manageable(ccstr, HeapDumpPath, NULL,                                     \
        "When HeapDumpOnOutOfMemoryError is on, the path (filename or"    \
        "directory) of the dump file (defaults to java_pid<pid>.hprof"    \
        "in the working directory)")                                      \

可以看到,除了HeapDumpOnOutOfMemoryError之外,还有HeapDumpBeforeFullGCHeapDumpAfterFullGC参数,分别用于指定在full GC之前与之后生成heap dump。

顺带一提,前面VisualVM的截图里“Disable Heap Dump on OOME”的功能,就是通过HotSpotDiagnosticMXBean将HeapDumpOnOutOfMemoryError参数设置为false来实现的。

======================================================================

通过JMX API在full GC前后生成heap dump的例子

原始代码放在这里了:https://gist.github.com/978336

很简单,就是演示了:
·获取HotSpotDiagnosticMXBean;
·通过它上面的setVMOption(String name, String value)方法修改HeapDumpBeforeFullGCHeapDumpAfterFullGC参数为true;
·触发一次full GC;
·将VM参数恢复为false。

为了方便,例子用Groovy来写。要在Groovy Shell中看到GC的日志,可以设置环境变量JAVA_OPTIONS=-XX:+PrintGCDetails,或者是在当前目录放一个.hotspotrc来配置这个参数;我是用的后者。

具体代码:
$ groovysh
[GC [PSYoungGen: 14016K->1312K(16320K)] 14016K->1312K(53696K), 0.0111510 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
[GC [PSYoungGen: 15328K->2272K(30336K)] 15328K->4832K(67712K), 0.0286280 secs] [Times: user=0.02 sys=0.03, real=0.03 secs] 
Groovy Shell (1.7.7, JVM: 1.6.0_25)
Type 'help' or '\h' for help.
----------------------------------------------------------------------------------------------------------------------------
groovy:000> import java.lang.management.ManagementFactory
===> [import java.lang.management.ManagementFactory]
groovy:000> import com.sun.management.HotSpotDiagnosticMXBean
===> [import java.lang.management.ManagementFactory, import com.sun.management.HotSpotDiagnosticMXBean]
groovy:000> 
groovy:000> HOTSPOT_BEAN_NAME = "com.sun.management:type=HotSpotDiagnostic"
===> com.sun.management:type=HotSpotDiagnostic
groovy:000> server = ManagementFactory.platformMBeanServer
[GC [PSYoungGen: 30304K->2288K(30336K)] 32864K->8856K(67712K), 0.0643130 secs] [Times: user=0.16 sys=0.01, real=0.07 secs] 
===> com.sun.jmx.mbeanserver.JmxMBeanServer@7297e3a5
groovy:000> bean = ManagementFactory.newPlatformMXBeanProxy(server, HOTSPOT_BEAN_NAME, HotSpotDiagnosticMXBean)
===> MXBeanProxy(com.sun.jmx.mbeanserver.JmxMBeanServer@7297e3a5[com.sun.management:type=HotSpotDiagnostic])
groovy:000> bean.setVMOption('HeapDumpBeforeFullGC', 'true')
===> null
groovy:000> bean.setVMOption('HeapDumpAfterFullGC', 'true')
===> null
groovy:000> System.gc()
[GC [PSYoungGen: 10460K->2288K(58368K)] 17028K->9639K(95744K), 0.0166920 secs] [Times: user=0.03 sys=0.00, real=0.02 secs] 
[Heap Dump: Dumping heap to java_pid16836.hprof ...
Heap dump file created [20066598 bytes in 0.347 secs]
, 0.3514030 secs][Full GC (System) [PSYoungGen: 2288K->0K(58368K)] [PSOldGen: 7351K->9621K(37376K)] 9639K->9621K(95744K) [PSPermGen: 18626K->18626K(37824K)], 0.1324840 secs] [Times: user=0.12 sys=0.02, real=0.14 secs] 
[Heap DumpDumping heap to java_pid16836.hprof.1 ...
Heap dump file created [20013677 bytes in 0.340 secs]
, 0.3398950 secs]===> null
groovy:000> bean.setVMOption('HeapDumpBeforeFullGC', 'false')
===> null
groovy:000> bean.setVMOption('HeapDumpAfterFullGC', 'false')
===> null
groovy:000> quit
Heap
 PSYoungGen      total 58368K, used 9250K [0x00000000edc00000, 0x00000000f1740000, 0x0000000100000000)
  eden space 56064K, 16% used [0x00000000edc00000,0x00000000ee5089b0,0x00000000f12c0000)
  from space 2304K, 0% used [0x00000000f1500000,0x00000000f1500000,0x00000000f1740000)
  to   space 2304K, 0% used [0x00000000f12c0000,0x00000000f12c0000,0x00000000f1500000)
 PSOldGen        total 37376K, used 9621K [0x00000000c9400000, 0x00000000cb880000, 0x00000000edc00000)
  object space 37376K, 25% used [0x00000000c9400000,0x00000000c9d65410,0x00000000cb880000)
 PSPermGen       total 37824K, used 18758K [0x00000000c4200000, 0x00000000c66f0000, 0x00000000c9400000)
  object space 37824K, 49% used [0x00000000c4200000,0x00000000c5451ba8,0x00000000c66f0000)

这样就得到了 java_pid16836.hprof 与 java_pid16836.hprof.1 两个heap dump文件。

把第二个heap dump文件改名为 java_pid16836.1.hprof 之后,用MAT打开这两个heap dump,在第一个文件的histogram试图下可以看到


目前MAT只支持histogram试图中比较两个heap dump。
点击上方工具条最右边的“<->”按钮,并选上第二个heap dump文件之后,可以看到:


这样就能很方便的得知这次full GC当中到底收集了多少个什么类型的对象。
实际效果跟手动用jmap -histo比较差不多,不过要精确的在full GC前后手动做些操作不是件简单的事情。

或许会有人想说,为啥MAT不能直接把具体是哪些对象被收集了显示出来呢?
这功能不好做。GC的时候对象可能会被移动,也就是说不能通过地址来将full GC前后的两个heap dump里的记录关联到一起;而HPROF格式也没有记录足够信息让多个heap dump之间能建立起联系。
结果能很方便做比较的就只有按类型做的统计。通常这也能提供有用的头绪去进一步做分析了。

P.S. 如果一个HPROF的heap dump是在开了压缩指针的64位JVM上生成的,那么用MAT查看的时候,里面显示的Shallow Heap和Retained Heap数据都会是错误的。因为HPROF格式只能分辨是32位还是64位的,却没有记录有没有开压缩指针、每个对象实际的大小是多少。这种条件下请不要相信MAT(或其它分析HPROF格式的heap dump的工具)显示的对象大小。
  • 大小: 128.8 KB
  • 大小: 212 KB
  • 大小: 72.4 KB
  • 大小: 140.5 KB
  • 大小: 119.1 KB
  • 大小: 35.3 KB
分享到:
评论
9 楼 RednaxelaFX 2011-05-19  
agapple 写道
因为在sun网站没找到一个地方能很全面的介绍这些参数内容

对了,Sun的网站上以前有人放过一份非官方的参数列表的,也可以参考:
http://blogs.sun.com/watt/resource/jvm-options-list.html
不过比较老了…
8 楼 RednaxelaFX 2011-05-18  
agapple 写道
应该是今年3月份,在滨江公司参加的分享,不知你是否还有印象?

还有一个问题,就是在验证一些逃逸优化时,有些jvm参数用不了,比如-XX:printInlining,-XX:printAssembly,jdk用的是1.6.11和jdk1.6.18

这些参数使用是否有特别的讲究,还是在特定的jdk版本之后才能使用?

啊啊,原来是B2B那次。呵呵,见笑了
时间上应该今年1月中旬吧。其实用的就是这个演示稿,只不过没有足够时间把那么多内容都塞进来。
印象中那次分享后我是发过这个演示稿给hongjiang的…呃,难道漏了。

agapple 写道
还有一个问题,就是在验证一些逃逸优化时,有些jvm参数用不了,比如-XX:printInlining,-XX:printAssembly,jdk用的是1.6.11和jdk1.6.18

-XX:+PrintInlining在product build的Sun JDK上可以是可以用,但什么也显示不出来。要在debug build(debug或者fastdebug)上才有意义。

-XX:PrintAssembly的使用请参考这篇文章:JVM 反汇编动态运行代码

简单来说,如果在声明那些VM参数的地方,写着是product、product_pd、diagnostic或者manageable的,那就是在平时用的product build里可以用的。其它都至少得在fastdebug build里才可以用。
7 楼 agapple 2011-05-18  
RednaxelaFX 写道
agapple 写道
多谢,原来kenwu叫晓峰啊。他的blog文章基本都看过,写的比较通俗,不错。

晓峰是他在淘宝的花名

agapple 写道
之前听过一次你的分享,讲的知识点不够多啊,还是这pdf给力。原先看的时候好几页关于锁的优化是空白页?是本身就没有还是pdf的原因?

请问哪一次分享?我这演示稿是去年年初开始一直在演化中的。今年3月底也有添加过少量内容不过没啥实质性提升所以还没发新版本出来。
那些空白页不是PDF的问题也不是有啥需要隐藏的信息,纯粹是我没写任何内容上去…最初我是拿这演示稿当mind map用的,方便我自己组织资料用。所以有些空白页慢慢的才会填上内容——如果我有时间的话 ^_^


应该是今年3月份,在滨江公司参加的分享,不知你是否还有印象?

还有一个问题,就是在验证一些逃逸优化时,有些jvm参数用不了,比如-XX:printInlining,-XX:printAssembly,jdk用的是1.6.11和jdk1.6.18

这些参数使用是否有特别的讲究,还是在特定的jdk版本之后才能使用?
6 楼 RednaxelaFX 2011-05-18  
agapple 写道
多谢,原来kenwu叫晓峰啊。他的blog文章基本都看过,写的比较通俗,不错。

晓峰是他在淘宝的花名

agapple 写道
之前听过一次你的分享,讲的知识点不够多啊,还是这pdf给力。原先看的时候好几页关于锁的优化是空白页?是本身就没有还是pdf的原因?

请问哪一次分享?我这演示稿是去年年初开始一直在演化中的。今年3月底也有添加过少量内容不过没啥实质性提升所以还没发新版本出来。
那些空白页不是PDF的问题也不是有啥需要隐藏的信息,纯粹是我没写任何内容上去…最初我是拿这演示稿当mind map用的,方便我自己组织资料用。所以有些空白页慢慢的才会填上内容——如果我有时间的话 ^_^
5 楼 agapple 2011-05-18  
RednaxelaFX 写道
agapple 写道
问个问题,LZ一般是通过什么方式获取一些jvm参数信息?直接看c源码?能给出几个源文件不?

因为在sun网站没找到一个地方能很全面的介绍这些参数内容

Oracle的官网上关于VM参数的文档主要就是这个:http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html
同事晓峰翻译过上面的文档:Java6 JVM参数选项大全(中文版)发布!

不过要问我是如何看参数的话,我自己确实是直接看源码的…
其实以前已经写过如何找这些参数了。请参考以前的一个演示稿的第236页。


多谢,原来kenwu叫晓峰啊。他的blog文章基本都看过,写的比较通俗,不错。

oracle官网上的那url以前基本也都看过,但看LZ你一些文章提的很多参数在上面都找不着影,所以有此一问。

之前听过一次你的分享,讲的知识点不够多啊,还是这pdf给力。原先看的时候好几页关于锁的优化是空白页?是本身就没有还是pdf的原因?
4 楼 RednaxelaFX 2011-05-18  
Mr.Chris 写道
撒迦的博客我什么时候能看懂啊 :)

诶诶…很晦涩么?什么部分?
3 楼 RednaxelaFX 2011-05-18  
agapple 写道
问个问题,LZ一般是通过什么方式获取一些jvm参数信息?直接看c源码?能给出几个源文件不?

因为在sun网站没找到一个地方能很全面的介绍这些参数内容

Oracle的官网上关于VM参数的文档主要就是这个:http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html
同事晓峰翻译过上面的文档:Java6 JVM参数选项大全(中文版)发布!

不过要问我是如何看参数的话,我自己确实是直接看源码的…
其实以前已经写过如何找这些参数了。请参考以前的一个演示稿的第236页。
2 楼 Mr.Chris 2011-05-18  
撒迦的博客我什么时候能看懂啊 :)
1 楼 agapple 2011-05-18  
问个问题,LZ一般是通过什么方式获取一些jvm参数信息?直接看c源码?能给出几个源文件不?

因为在sun网站没找到一个地方能很全面的介绍这些参数内容

相关推荐

    weblogic内存调优

    JVM内存的调优 ...当该区被填满时,GC会将对象移到Old区。Permanent区则负责保存反射对象,本文不讨论该区。JVM的Heap分配可以使用-X参数设定, -Xms 初始Heap大小 -Xmx java heap最大值 …… ……

    Zabbix通过JMX方式监控java中间件

    Zabbix通过JMX方式监控java中间件 Zabbix2.0添加了支持用于监控JMX应用程序的服务进程,称为“Zabbix-Java-gateway”;它是用java写的一个程序。 工作原理: zabbix_server想知道一台主机上的特定的JMX值时,它向...

    jmx-dump:将JMX指标作为JSON转储到命令行

    在命令行上将JMX指标转储为JSON。 安装 从下载独立的二进制文件或jar。 也可以通过自制水龙头使用 brew tap r4um/homebrew brew install jmx-dump 旧版本。 用法 使用发行版中的独立二进制文件或jar。 $ jmx-dump...

    通过jmx监控管理weblogic

    JMX(Java Management Extensions)是SUN创建的一套规范。BEA WebLogic Server实现了JMX大部分的API,并且提供了一个完全兼容JMX的控制台来管理各种资源。OPEN SOURCE的应用服务器JBoss也是基于JMX来实现。并且对之评价...

    JMX实战 JMX开发

    JMX实战 书中不仅有对于基础知识的介绍,还有对于JMX开发中重大的体系架构问题的深入探讨,总结了大量JMX开发中的设计模式,并讨论了框架、安全性与性能等等。书中提供了几个典型的例子,兼顾各种开发平台,这些...

    JMX 在GlassFish中的应用

    jmx和jmx在glassfish中的应用

    jmx入门

    为什么JMX那么受欢迎,JMX到底有那些优势只得人们去学习和理解,本文从JMX的基本架构、hellowold jmx以及spring对JMX的支持讲起,希望大家能通过本文对JMX有个基础的认识,并能通过本文为今后学习JMX打个基础

    jmx一步步来 jmx快速上手指南

    jmx快速上手 jmx快速上手 jmx快速上手 jmx快速上手

    Fiddler导出jmx文件

    Fiddler导出jmx文件,解决Fiddler导出文件中 没有jmx文件选项,各个版本fiddler都适用

    亲测可用 com.sun.jmx. jmxri-1.2.1.jar

    Description Resource Path Location Type Missing artifact com.sun.jmx:jmxri:jar:1.2.1 pom.xml /eshop-storm line 2 Maven Dependency Problem

    Zabbix通过JMX监控java中间件.docx

    Zabbix通过JMX监控java中间件.docx

    jmx-jvm配置

    jmx配置

    JBoss JMX实现架构

    JBoss JMX实现架构 JBoss JMX实现架构

    jmx监控tomcat测试包

    catalina-jmx-remote.jar放到tomcat/lib目录下 如果是windows版本,编辑TOMCAT_HOME/bin/catalina.bat,在开头加入下面几行: set CATALINA_OPTS=%CATALINA_OPTS% -Djava.rmi.server.hostname=JMX_HOST set CATALINA...

    jmx 实例 rmi mbean

    jmx 实例 rmi mbean,采用rmi方式进行jmx的mbean管理,通过这个实例能够了解jmx的应用

    JMX小例子以及介绍

    JMX小例子以及介绍 JMX小例子以及介绍 JMX小例子以及介绍

    Jmx实例demo下载

    java实现Jmx实例,jmxdemo项目源码下载

    jmx监控weblogic,tomcat,websphere源码

    java项目,自己做的项目利用jmx监控weblogic,tomcat,websphere源码

    JMX与JMS的概念

    JMX与JMS的概念

    JMX一步一步来,快速学会开发JMX应用

    JMX一步一步来,从最基本的应用开始入手,快速应用开发。

Global site tag (gtag.js) - Google Analytics