`
RednaxelaFX
  • 浏览: 3057542 次
  • 性别: 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网站没找到一个地方能很全面的介绍这些参数内容

相关推荐

    Heap Dump的IBM分析工具.zip

    1. **生成heap dump**:在JVM启动时添加`-XX:+HeapDumpOnOutOfMemoryError`参数,或者通过JMX、JConsole等方式手动触发dump生成。 2. **下载并安装分析工具**:如VisualVM或MAT,确保其版本与JVM兼容。 3. **加载...

    IBM WebSphere Heapdump Analyzer

    这通常可以通过在WebSphere Application Server的管理控制台或通过JMX接口触发。一旦有了heapdump文件,就可以使用`StartHeapAnalyzer.bat`启动工具,并导入heapdump进行分析。分析结果可以帮助定位内存问题,进一步...

    jvm-full-gc调优-jvm-full-gc.zip

    在Java开发中,JVM(Java虚拟机)的性能优化是一项关键任务,特别是对于大型系统而言,频繁的Full GC(垃圾收集)会导致应用暂停时间过长,影响用户体验。本资料"jvm-full-gc调优-jvm-full-gc.zip"显然是针对如何...

    weblogic内存调优

    老年代用于存储长期存活的对象,当老年代空间不足时,会触发Major GC或Full GC,这可能会导致服务短暂暂停。 内存调优的目标是平衡内存使用和垃圾收集的效率。-Xmn参数可以设置年轻代的大小,通常建议将其设置为堆...

    jvm-full-gc.zip

    为了更好地理解和调优Full GC,我们可以借助JDK自带的JConsole、VisualVM、JFR(Java Flight Recorder)以及JMX等工具进行监控。它们能提供详细的GC日志,帮助我们分析Full GC的触发原因和性能瓶颈。 总结,理解JVM...

    FullGC的样例报告

    首先,我们关注"元空间不足导致频繁FullGC.pdf"这个文件。元空间是Java 8引入的新特性,取代了之前的永久代(Permanent Generation)。元空间主要存储类的元数据,如类信息、方法信息、字段信息等。当元空间满时,...

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

    Zabbix 通过 JMX 监控 Java 中间件的工作原理是:Zabbix 服务器想知道一台主机上的特定的 JMX 值时,它向 Zabbix-Java-gateway 询问,而 Zabbix-Java-gateway 使用“JMX management API”去查询特定的应用程序,前提...

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

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

    java 内存dump分析和thread dump(java core)分析

    通过JMX连接到运行中的JVM进行实时监控。 3. **YourKit Java Profiler**:一款强大的商业工具,提供详细的内存分配和存活路径分析,界面友好且功能强大。 4. **JProfiler**:另一款强大的商业Java性能分析器,支持...

    ibm HeapAnalyzer JVM内存分析工具 ha457.jar下载

    同时,理解如何在Java应用中生成堆转储文件也是必不可少的,这通常可以通过JVM的命令行选项或者JMX接口来实现。 总之,IBM HeapAnalyzer是Java开发者诊断和修复内存问题的强大武器。通过熟练使用这个工具,你可以...

    jmx三种访问方式

    2. **JVisualVM**:JVisualVM(包含在JDK中)也支持通过VM参数连接到远程JMX服务器。除了基本的JMX功能外,它还提供了内存分析、线程分析等高级功能。 3. **命令行工具**:除了图形工具,还可以通过命令行工具jcmd...

    通过jmx监控管理weblogic

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

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

    在Zabbix 2.0版本中引入了一个新的特性——通过**JMX (Java Management Extensions)**的方式监控Java应用。JMX是一种标准的Java技术,用于管理Java应用和系统。通过JMX,开发人员和系统管理员可以远程监控和管理运行...

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

    MBeans提供了暴露其状态和操作的方法,使得管理者可以通过JMX API进行访问和控制。例如,通过JMX,你可以动态地修改应用的配置参数,监控系统的性能指标,甚至触发特定的操作。 传统的配置方式通常需要修改源代码...

    jmx监控activeMQ监控

    通过jmx监控,可以快速地检测和解决ActiveMQ中的问题,从而提高系统的可靠性和稳定性。 在生产环境中,jmx监控是非常重要的,可以帮助开发者和运维人员实时监控ActiveMQ的运行状态,快速检测和解决问题。同时,jmx...

    jboss远程调用JMX

    当我们谈论"jboss远程调用JMX"时,我们关注的是如何通过网络从一个JMX客户端连接到运行在JBoss服务器上的JMX服务,以便进行远程管理和监控。 首先,我们需要了解JMX的基本概念。MBean是JMX的核心,它是一个Java对象...

    Hbase和Hadoop JMX监控实战

    在监控HBase时,我们可以通过JMX获取HMaster、RegionServer等组件的状态,包括 Region分布、内存使用情况、StoreFile数量、请求数量等。例如,可以使用JMX客户端工具如jconsole或jmxterm来连接到运行中的HBase集群,...

    java应用JVM的GC频率观察方法

    年轻代GC主要处理新生代的对象,而Full GC则涉及到整个堆,包括年轻代和老年代,它的执行通常会导致较高的系统负载,并可能导致应用程序暂停,甚至在频繁触发时造成服务中断或系统崩溃。 为了确保应用的稳定性和...

    jmx监控weblogic,tomcat,websphere源码

    在本项目中,"jmx监控weblogic,tomcat,websphere源码"涉及了使用JMX来监控三个主流的Java应用服务器:WebLogic、Tomcat和WebSphere。这些服务器都是企业级应用部署的常见选择,对它们的监控对于确保系统性能、稳定性...

Global site tag (gtag.js) - Google Analytics