JAVA JVM 支持所以的标准命令选项,标准选项用于常见操作,例如检查JRE版本,设置类路径,启用详细输出等
-agentlib:<libname>[=<选项>]
加载指定的本机代理程序库。libname 后面 可以使用逗号分隔的特定于该库的选项列表。
本章详细讲解 本地代理库之 hprof 工具的使用指南,该工具是SDK自带的一个简单的profiler代理,它通过与Java Virtual Machine Profiler Interface (JVMPI) 交互,将profiling信息通过本地文件或socket输出ASCII或二进制格式的流
HPROF可以监控CPU使用率,堆分配统计。除此之外,还可以报告JVM所有监视器和线程的完整的堆的dump状态。
获取hprof帮助信息
java -agentlib:hprof=help
将显示如下帮助信息
详细参数列表如下:
java -agentlib:hprof=[help]|[<option>=<value>, ...]
参数和取值范围 | 默认值 | 说明 |
---|---|---|
heap=dump|sites|all | all | 堆分析( 详见 如下具体讲解 ) |
cpu=samples|times|old | off | CPU使用率 |
monitor=y|n | n | 监控资源 |
format=a|b | a | 输出为文本或者二进制( format=b 是实验性接口 ) |
file=<file> | java.hprof[{.txt}] | 将数据写入到文件 |
net=<host>:<port> | off | 通过socket发送数据 |
depth=<size> | 4 | 跟踪堆栈的深度 |
interval=<ms> | 10 | 采样的时间间隔 ms |
cutoff=<value> | 0.0001 | 结束点 |
lineno=y|n | y | 显示行号 |
thread=y|n | n | 根据线程 |
doe=y|n | y | 存储完毕,直接退出 |
msa=y|n | n | |
force=y|n | y | 强制输出到文件 |
verbose=y|n | y | 打印相关dumps的消息 |
已经过时的选项:gc_okay=y|n
默认情况下,堆分析信息(sites and dump)被写到当前工作目录中的java.hprof.txt(ASCII)。
尽管可以通过将 doe选项设置为n(doe = n)来禁用,但是通常在JVM退出时会依然生成输出文件。
另外,当按Ctrl + (在Oracle和Linux操作系统上)或Ctrl-Break(在Windows上)时,将生成一个配置文件。
在Oracle Solaris和Linux操作系统上,当进程接收到QUIT信号时,也会生成一个配置文件(kill -QUIT pid)。
如果多次按Ctrl + 或Ctrl-Break,则将一个文件生成多个配置文件。
在大多数情况下,输出内容将包含堆栈跟踪信息、线程和对象的ID。每种类型的ID通常以不同的数字开头。比如:堆栈跟踪是以 300000 开始
参数 heap=sites
javac -J-agentlib:hprof=heap=sites Hello.java
Hello.java 仅是示例程序
通过在一组输入文件上运行Java编译器(javac)生成的堆分配配置文件。这里仅显示探查器输出的一部分。
默认将会生成一个名为:java.hprof.txt 的文件,在文件中将会出现如下内容
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[]
堆概要文件中的关键信息是程序各个部分中发生的分配量。上面的记录显示,总空间的44.13%已分配给java.util.zip.ZipEntry对象。
将分配站点与源代码相关联的一种好方法是记录导致堆分配的动态堆栈跟踪。
如下示例显示了探查器输出的另一部分。它说明了前面输出中四个分配站点所引用的堆栈跟踪。
用于堆栈跟踪的探查器输出(Profiler Ouput for Stack Traces)
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代理收集的最大帧数。默认限制为四个。
堆栈跟踪不仅揭示了哪些方法执行堆分配,而且还揭示了哪些方法最终负责进行导致内存分配的调用。
参数 heap=dump
可以使用heap = dump选项获得堆的dump . 堆dump为ASCII或二进制格式,具体取决于format选项的设置。jhat之类的工具使用二进制格式,因此需要format = b选项。有关更多详细信息,请参见jhat Utility
https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr012.html#BABJGJBIdocs.oracle.com当指定二进制格式时,转储包括原始类型实例字段和原始数组内容。
如下示例 显示了通过执行javac编译器生成堆中当前活动对象的ASCII文本格式的完整转储的命令:
javac -J-agentlib:hprof=heap=dump Hello.java
文件内容如下
EAP 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
输出是一个比较大的文件。它包括由垃圾收集器确定的根集,以及可以从根集访问堆中每个Java对象的条目。
以下是样本堆转储中的记录选择。
每个记录都是ROOT,OBJ,CLS或ARR,它们代表根,对象实例,类或数组。十六进制数字是由HPROF分配的标识符。这些数字用于显示从一个对象到另一个对象的引用。
在上面的示例中,java.lang.Thread实例50000114引用了其线程组(50008c6c)和其他对象。
通常情况下,由于输出内容比较大,因此有必要使用工具来可视化或处理堆转储的输出。jhat 提供了这个功能
The jhat Utilitydocs.oracle.com关于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选项慢得多。
如下展示了从javac编译器运行中收集的部分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时间的度量
java -agentlib:jdwp
java -agentlib:jdwp=[help]|[<option>=<value>, ...]
Java Debugger JDWP 代理库 对于调试应用程序和小程序非常有用。
使用示例:
使用sockets连接到特定地址的调试器:
java -agentlib:jdwp=transport=dt_socket,address=localhost:8000 ...
使用sockets监听调试器附加:
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=y ...
参考资料
参考1docs.oracle.comJDWP协议规范文档:
Java Debug Wire Protocoldocs.oracle.com-agentpath:pathname[=options]
加载由绝对路径名指定的本机代理程序库。此选项等效于-agentlib,但使用库的完整路径和文件名。
有关本机代理程序库的更多信息,请参考以下内容:
java.lang.instrument 包描述
java.lang.instrument (Java Platform SE 8 )docs.oracle.comJVM工具界面指南中的代理程序命令行选项位于
JVM(TM) Tool Interface 1.2.3docs.oracle.com-javaagent:jarpath[=options]
加载指定的Java代理。有关检测Java应用程序的更多信息,请参阅Java API文档中的java.lang.instrument包描述。
java.lang.instrument (Java Platform SE 8 )docs.oracle.com