JPSE问题诊断指导四——hprof

HPROF是一个每个JDK发行版都会内置的堆和CPU分析工具。它是一个使用JVM TI和JVM交互的DLL。该工具可以将分析信息写入文件或者以ASCII或者二进制格式写入socket,这些信息将来可以用前端分析工具来处理。

HPROF工具能展现CPU使用、堆分配统计和监视内容分析。此外,它也能报告JVM中所有监视者和线程的完整堆dump和状态。就诊断的问题而言,HPROF在分析性能问题、锁争用、内存泄漏和其他问题时有用。

除了HPROF库之外,JDK还包含HPROF作为JVM TI演示的源码。代码位置在$JAVA_HOME/demo/jvmti/hprof

HPROF工具像下面那样调用:java -agentlib:hprof ToBeProfiledClass

取决于分析的请求类型,HPROF指示JVM去发送它到相关的事件。工具然后处理事件数据到分析信息中。例如,以下命令获取堆分配分析:java -agentlib:hprof=heap=sites ToBeProfiledClass

当HPROF代理以help选项提供时将会打印完整的选项列表:java -agentlib:hprof=help

C:\Users\lhl>java -agentlib:hprof=help

     HPROF: Heap and CPU Profiling Agent (JVMTI Demonstration Code)

hprof usage: java -agentlib:hprof=[help]|[<option>=<value>, ...]

Option Name and Value  Description                    Default
---------------------  -----------                    -------
heap=dump|sites|all    heap profiling                 all
cpu=samples|times|old  CPU usage                      off
monitor=y|n            monitor contention             n
format=a|b             text(txt) or binary output     a
file=<file>            write data to file             java.hprof[{.txt}]
net=<host>:<port>      send data over a socket        off
depth=<size>           stack trace depth              4
interval=<ms>          sample interval in ms          10
cutoff=<value>         output cutoff point            0.0001
lineno=y|n             line number in traces?         y
thread=y|n             thread in traces?              n
doe=y|n                dump on exit?                  y
msa=y|n                Solaris micro state accounting n
force=y|n              force output to <file>         y
verbose=y|n            print messages about dumps     y

Obsolete Options
----------------
gc_okay=y|n

Examples
--------
  - Get sample cpu information every 20 millisec, with a stack depth of 3:
      java -agentlib:hprof=cpu=samples,interval=20,depth=3 classname
  - Get heap usage information based on the allocation sites:
      java -agentlib:hprof=heap=sites classname

Notes
-----
  - The option format=b cannot be used with monitor=y.
  - The option format=b cannot be used with cpu=old|times.
  - Use of the -Xrunhprof interface can still be used, e.g.
       java -Xrunhprof:[help]|[<option>=<value>, ...]
    will behave exactly the same as:
       java -agentlib:hprof=[help]|[<option>=<value>, ...]

Warnings
--------
  - This is demonstration code for the JVMTI interface and use of BCI,
    it is not an official product or formal part of the JDK.
  - The -Xrunhprof interface will be removed in a future release.
  - The option format=b is considered experimental, this format may change
    in a future release.

默认情况下,堆分析信息(site和dump)被写入当前目录的java.hprof.txt(ascii)

输出通常在JVM退出时生成,尽管这可以通过设置doe选项到n(doe=n)来禁用。此外,当ctrl+\或者ctrl+break按下时会产生一个分析文件。在oracle和Linux上面当进程收到一个QUIT信号时也会产生分析文件,如果ctrl+\或者ctrl+break按下多次,那么将产生多个分析到一个文件中。

多数情况下输出会包含跟踪的id、线程和对象。各种类型的id将会典型的以一个不同的数字开头。


堆分配分析 heap=sites

下面是一个通过在一个输入文件集上面运行javac生成的堆分配分析文件。这里只展示部分输出:


$javac -J-agentlib:hprof=heap=sites Hello.java
SITES BEGIN (ordered by live bytes) Wed Oct 4 13:13:42 2006
          percent          live          alloc'ed  stack class
 rank   self  accum     bytes objs     bytes  objs trace name
    1 44.13% 44.13%   1117360 13967  1117360 13967 301926 java.util.zip.ZipEntry
    2  8.83% 52.95%    223472 13967   223472 13967 301927 com.sun.tools.javac.util.List
    3  5.18% 58.13%    131088    1    131088     1 300996 byte[]
    4  5.18% 63.31%    131088    1    131088     1 300995 com.sun.tools.javac.util.Name[]
堆分析信息中一个至关重要的片段是程序不同部分发生的分配的数量。前面的SITES记录显示了总 空间的 44.13%是为java.util.zip.ZipEntry对象分配的。

一个好的关联allocation sites到源码的方法是记录导致堆分配的动态堆栈跟踪。一下输出显示了分析输出的另一部分,它演示了关于这4个allocation sites的堆栈跟踪。

TRACE 301926:
        java.util.zip.ZipEntry.<init>(ZipEntry.java:101)
        java.util.zip.ZipFile+3.nextElement(ZipFile.java:417)
        com.sun.tools.javac.jvm.ClassReader.openArchive(ClassReader.java:1374)
        com.sun.tools.javac.jvm.ClassReader.list(ClassReader.java:1631)
TRACE 301927:
        com.sun.tools.javac.util.List.<init>(List.java:42)
        com.sun.tools.javac.util.List.<init>(List.java:50)
        com.sun.tools.javac.util.ListBuffer.append(ListBuffer.java:94)
        com.sun.tools.javac.jvm.ClassReader.openArchive(ClassReader.java:1374)
TRACE 300996:
        com.sun.tools.javac.util.Name$Table.<init>(Name.java:379)
        com.sun.tools.javac.util.Name$Table.<init>(Name.java:481)
        com.sun.tools.javac.util.Name$Table.make(Name.java:332)
        com.sun.tools.javac.util.Name$Table.instance(Name.java:349)
TRACE 300995:
        com.sun.tools.javac.util.Name$Table.<init>(Name.java:378)
        com.sun.tools.javac.util.Name$Table.<init>(Name.java:481)
        com.sun.tools.javac.util.Name$Table.make(Name.java:332)
        com.sun.tools.javac.util.Name$Table.instance(Name.java:349)
堆栈中的每一帧都包含一个类名、一个方法名、一个源文件名和行号。用户可以设置HPROF代理可以收集的最大帧数,默认是4。堆栈不止揭示了哪个方法执行过堆分配,而且也揭露了哪个方法最终对标记导致内存分配的调用负责。


Heap Dump Profile heap=dump

一个堆dump可以通过heap=dump选项获得。堆dump可以是ascii或者二进制格式,取决于格式选项的设置。例如jhat这样的工具使用二进制格式所以format=b选项必须要设置。当指定了二进制格式时,dump包含原始类型实例字段和原始数组内容。

下面的命令从执行javac编译器的堆中产生一个当前存活对象的完整的ascii文本格式的dump:

avac -J-agentlib:hprof=heap=dump Hello.java
输出是一个非常大的文件。它包含GC决定的根节点,和堆中根节点可达的每个java对象的入口。下面是一个简单堆dump的部分:


HEAP DUMP BEGIN (39793 objects, 2628264 bytes) Wed Oct 4 13:54:03 2006
ROOT 50000114 (kind=<thread>, id=200002, trace=300000)
ROOT 50000006 (kind=<JNI global ref>, id=8, trace=300000)
ROOT 50008c6f (kind=<Java stack>, thread=200000, frame=5)
:
CLS 50000006 (name=java.lang.annotation.Annotation, trace=300000)
    loader        90000001
OBJ 50000114 (sz=96, trace=300001, class=java.lang.Thread@50000106)
    name        50000116
    group        50008c6c
    contextClassLoader    50008c53
    inheritedAccessControlContext    50008c79
    blockerLock    50000115
OBJ 50008c6c (sz=48, trace=300000, class=java.lang.ThreadGroup@50000068)
    name        50008c7d
    threads    50008c7c
    groups        50008c7b
ARR 50008c6f (sz=16, trace=300000, nelems=1, 
     elem type=java.lang.String[]@5000008e)
    [0]        500007a5
CLS 5000008e (name=java.lang.String[], trace=300000)
    super        50000012
    loader        90000001
:
HEAP DUMP END
每个记录都是一个ROOT,OBJ,CLS或者ARR,分别对应root,一个对象实例,一个类,或者一个数组。16进制数字是HPROF分配的标识,这些数字被用来显示一个对象到另一个对象的引用。在前面的例子中java.lang.Thread实例50000114有一个到它的线程组50008c6c和其他对象的引用。


通常情况下,由于输出非常大,有一个工具来可视化或者处理堆dump的输出很有必要。例如jhat。

CPU使用采样分析cpu=samples

HPROF工具能通过采样线程来收集CPU使用率信息。下面的例子显示了如何通过运行javac编译器来生成一个CPU使用率采样分析:

javac -J-agentlib:hprof=cpu=samples Hello.java
CPU SAMPLES BEGIN (total = 462) Wed Oct 4 13:33:07 2006
rank   self  accum   count trace method
   1 49.57% 49.57%     229 300187 java.util.zip.ZipFile.getNextEntry
   2  6.93% 56.49%      32 300190 java.util.zip.ZipEntry.initFields
   3  4.76% 61.26%      22 300122 java.lang.ClassLoader.defineClass2
   4  2.81% 64.07%      13 300188 java.util.zip.ZipFile.freeEntry
   5  1.95% 66.02%       9 300129 java.util.Vector.addElement
   6  1.73% 67.75%       8 300124 java.util.zip.ZipFile.getEntry
   7  1.52% 69.26%       7 300125 java.lang.ClassLoader.findBootstrapClass
   8  0.87% 70.13%       4 300172 com.sun.tools.javac.main.JavaCompiler.<init>
   9  0.65% 70.78%       3 300030 java.util.zip.ZipFile.open
  10  0.65% 71.43%       3 300175 com.sun.tools.javac.main.JavaCompiler.<init>

...
CPU SAMPLES END
HPROF代理周期性的采样所有运行中的线程堆栈以记录最活跃的堆栈跟踪。上面的count字段预示了一个堆栈被发现活跃了多少次。这些堆栈跟踪对应到应用中的CPU使用热点。


CPU使用时间分析cpu=times

HPROF工具能通过注入代码到每个方法的入口和出口来收集CPU使用信息,从而跟踪确切方法的调用次数和每个方法花费的时间。这个进程使用字节码索引(BCI)并运行得比cpu=samples要慢。下面的例子显示了部分CPU使用时间分析输出:

$javac -J-agentlib:hprof=cpu=times Hello.java
CPU TIME (ms) BEGIN (total = 2082665289) Wed oct 4 13:43:42 2006
rank   self  accum   count trace method
   1  3.70%  3.70%       1 311243 com.sun.tools.javac.Main.compile
   2  3.64%  7.34%       1 311242 com.sun.tools.javac.main.Main.compile
   3  3.64% 10.97%       1 311241 com.sun.tools.javac.main.Main.compile
   4  3.11% 14.08%       1 311173 com.sun.tools.javac.main.JavaCompiler.compile
   5  2.54% 16.62%       8 306183 com.sun.tools.javac.jvm.ClassReader.listAll
   6  2.53% 19.15%      36 306182 com.sun.tools.javac.jvm.ClassReader.list
   7  2.03% 21.18%       1 307195 com.sun.tools.javac.comp.Enter.main
   8  2.03% 23.21%       1 307194 com.sun.tools.javac.comp.Enter.complete
   9  1.68% 24.90%       1 306392 com.sun.tools.javac.comp.Enter.classEnter
  10  1.68% 26.58%       1 306388 com.sun.tools.javac.comp.Enter.classEnter
...
CPU TIME (ms) END
这个输出中,count表示这个方法进入的真实次数,百分比表示这个方法消耗的线程cpu时间。



转载于:https://my.oschina.net/codefire/blog/372181

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值