本文向各位介绍一下Java性能监控小技巧:“JDK附带分析器、远程连接进程、跟踪统计、为离线分析创建一个堆转储、JConsole并不是高深莫测的。”
5个命令行分析工具
全功能内置分析器,如JConsole和VisualVM的成本有时比它们的性能费用还要高—尤其是在生产软件上运行的系统中。因此,在聚焦Java性能监控的第2篇中,我将介绍5个命令行分析工具,使开发人员仅关注运行的Java进程的一个方面。
JDK包括很多命令行实用程序,可以用于监控和管理Java应用程序性能。虽然大多数这类应用程序都被标注为“实验型”,在技术上不受支持,但是它们很有用。
1.jps(sun.tools.jps)
查看进程ID
很多命令行工具都要求您识别您希望监控的Java进程。这与监控本地操作系统进程、同样需要一个程序识别器的同类工具没有太大区别。
“VMID”识别器与本地操作系统进程识别器(“pid”)并不总是相同的,这就是我们需要JDKjps实用程序的原因。
在Java进程中使用jps
与配置JDK的大部分工具及本文中提及的所有工具一样,可执行jps通常是一个围绕Java类或执行大多数工作的类集的一个薄包装。在Windows®环境下,这些工具是.exe文件,使用JNIInvocationAPI直接调用上面提及的类;在UNIX®环境下,大多数工具是一个shell脚本的符号链接,该脚本采用指定的正确类名称开始一个普通启动程序。如果您希望在Java进程中使用jps(或者任何其他工具)的功能—Ant脚本—仅在每个工具的“主”类上调用main()相对容易。为了简化引用,类名称出现在每个工具名称之后的括号内。
jps—名称反映了在大多数UNIX系统上发现的ps实用程序—告诉我们运行Java应用程序的JVMID。顾名思义,jps返回指定机器上运行的所有已发现的Java进程的VMID。如果jps没有发现进程,并不意味着无法附加或研究Java进程,而只是意味着它并未宣传自己的可用性。
如果发现Java进程,jps将列出启用它的命令行。这种区分Java进程的方法非常重要,因为只要涉及操作系统,所有的Java进程都被统称为“java”。在大多数情况下,VMID是值得注意的重要数字。
使用分析器开始
使用分析实用程序开始的最简单方法是使用一个如在demo/jfc/SwingSet2中发现的SwingSet2演示一样的演示程序。这样就可以避免程序作为背景/监控程序运行时出现挂起的可能性。当您了解工具及其费用后,就可以在实际程序中进行试用。
加载演示应用程序后,运行jps并注意返回的vmid。为了获得更好的效果,采用-Dcom.sun.management.jmxremote属性集启动Java进程。如果没有使用该设置,部分下列工具收集的部分数据可能不可用。
2.jstat(sun.tools.jstat)
查看内存情况
jstat实用程序可以用于收集各种各样不同的统计数据。jstat统计数据被分类到“选项”中,这些选项在命令行中被指定作为第一参数。对于JDK 1.6来说,您可以通过采用命令-options运行jstat查看可用的选项清单。清单1中显示了部分选项:
清单1.jstat选项
1.
2.
3. -class
4. -compiler
5. -gc
6. -gccapacity
7. -gccause
8. -gcnew
9. -gcnewcapacity
10. -gcold
11. -gcoldcapacity
12. -gcpermcapacity
13. -gcutil
14. -printcompilation
实用程序的JDK记录将告诉您清单1中每个选项返回的内容,但是其中大多数用于收集垃圾的收集器或者其部件的性能信息。-class选项显示了加载及未加载的类(使其成为检测应用程序服务器或代码中ClassLoader泄露的重要实用程序,且-compiler和-printcompilation都显示了有关Hotspot JIT编译程序的信息。
默认情况下,jstat在您核对信息时显示信息。如果您希望每隔一定时间拍摄快照,请在-options指令后以毫秒为单位指定间隔时间。jstat将持续显示监控进程信息的快照。如果您希望jstat在终止前进行特定数量的快照,在间隔时间/时间值后指定该数字。
如果5756是几分钟前开始的运行SwingSet2程序的VMID,那么下列命令将告诉jstat每250毫秒为10个佚代执行一次gc快照转储,然后停止:
15. jstat -gc 5756 250 10
请注意Sun(现在的Oracle)保留了在不进行任何预先通知的情况下更改各种选项的输出甚至是选项本身的权利。这是使用不受支持实用程序的缺点。请参看Javadocs了解jstat输出中每一列的全部细节。
http://xueliang880107.iteye.com/blog/954073
- S0 — Heap上的 Survivor space 0 区已使用空间的百分比
- S1 — Heap上的 Survivor space 1 区已使用空间的百分比
- E — Heap上的 Eden space 区已使用空间的百分比
- O — Heap上的 Old space 区已使用空间的百分比
- P — Perm space 区已使用空间的百分比
- YGC — 从应用程序启动到采样时发生 Young GC 的次数
- YGCT– 从应用程序启动到采样时 Young GC 所用的时间(单位秒)
- FGC — 从应用程序启动到采样时发生 Full GC 的次数
- FGCT– 从应用程序启动到采样时 Full GC 所用的时间(单位秒)
- GCT — 从应用程序启动到采样时用于垃圾回收的总时间(单位秒)
3.jstack(sun.tools.jstack)
查看线程情况
了解Java进程及其对应的执行线程内部发生的情况是一种常见的诊断挑战。例如,当一个应用程序突然停止进程时,很明显出现了资源耗尽,但是仅通过查看代码无法明确知道何处出现资源耗尽,且为什么会发生。
jstack是一个可以返回在应用程序上运行的各种各样线程的一个完整转储的实用程序,您可以使用它查明问题。
采用期望进程的VMID运行jstack会产生一个堆转储。就这一点而言,jstack与在控制台窗口内按Ctrl-Break键起同样的作用,在控制台窗口中,Java进程正在运行或调用VM内每个Thread对象上的Thread.getAllStackTraces()或Thread.dumpStack()。jstack调用也转储关于在VM内运行的非Java线程的信息,这些线程作为Thread对象并不总是可用的。
jstack的-l参数提供了一个较长的转储,包括关于每个Java线程持有锁的更多详细信息,因此发现(和squash)死锁或可伸缩性bug是极其重要的。
4.jmap(sun.tools.jmap)
查看内存堆情况
有时,您正在处理的问题是一个对象泄露,如一个ArrayList(可能持有成千上万个对象)该释放时没有释放。另一个更普遍的问题是,看似从不会压缩的扩展堆,却有活跃的垃圾收集。
当您努力寻找一个对象泄露时,在指定时刻对堆及时进行拍照,然后审查其中内容非常有用。jmap通过对堆拍摄快照来提供该功能的第一部分。然后您可以采用下一部分中描述的jhat实用程序分析堆数据。
与这里描述的其他所有实用程序一样,使用jmap非常简单。将jmap指向您希望拍快照的Java进程的VMID,然后给予它部分参数,用来描述产生的结果文件。您要传递给jmap的选项包括转储文件的名称以及是否使用一个文本文件或二进制文件。二进制文件是最有用的选项,但是只有当与某一种索引工具结合使用时—通过十六进制值的文本手动操作数百兆字节不是最好的方法。
随意看一下Java堆的更多信息,jmap同样支持-histo选项。-histo产生一个对象文本柱状图,现在在堆中大量引用,由特定类型消耗的字节总数分类。它同样给出了特定类型的总示例数量,支持部分原始计算,并猜测每个实例的相对成本。
不幸的是,jmap没有像jstat一样的period-and-max-count选项,但是将jmap(或jmap.main())调用放入shell脚本或其他类的循环,周期性地拍摄快照相对简单。(事实上,这是加入jmap的一个好的扩展,不管是作为OpenJDK本身的源补丁,还是作为其他实用程序的扩展。)
Eclipse Memory Analyzer是Eclipse提供的一个用于分析jvm堆dump文件的插件,借助这个插件可查看对象的内存占用状况、引用关系、分析内存泄露等。
Eclipse Memory Analyzer(MAT)的网站为:,在eclipse中可以直接远程安装此插件。不过由于此插件在分析堆dump文件时比较耗内存,因此在分析前最好先将eclipse的jvm的内存设置大一点,MAT分析dump文件后的对象占用内存及引用关系如图3.23所示。
相对而言MAT功能比jhat强大很多,分析的速度也快一些,因此,如果要分析jvm堆dumap文件,首选推荐的是MAT。
5.jhat(com.sun.tools.hat.Main)
与jmap配合使用,用于浏览jmao生成的文件
将堆转储至一个二进制文件后,您就可以使用jhat分析二进制堆转储文件。jhat创建一个HTTP/HTML服务器,该服务器可以在浏览器中被浏览,提供一个关于堆的object-by-object视图,及时冻结。根据对象引用草率处理堆可能会非常可笑,您可以通过对总体混乱进行某种自动分析而获得更好的服务。幸运的是,jhat支持OQL语法进行这样的分析。
例如,对所有含有超过100个字符的String运行OQL查询看起来如下:
16. select s from java.lang.String s where s.count 》= 100
结果作为对象链接显示,然后展示该对象的完整内容,字段引用作为可以解除引用的其他链接的其他对象。OQL查询同样可以调用对象的方法,将正则表达式作为查询的一部分,并使用内置查询工具。一种查询工具,referrers()函数,显示了引用指定类型对象的所有引用。下面是寻找所有参考File对象的查询:
17. select referrers(f) from java.io.File f
您可以查找OQL的完整语法及其在jhat浏览器环境内“OQL Help”页面上的特性。将jhat与OQL相结合是对行为不当的堆进行对象调查的有效方法。
--------------------------------------------------------------------------------------------
./jps
./jstat -gcutil -h20 12834 1s
./jstack 12834 > /home/jstack1.logc
./jmap -dump:live,file=/mnt/dump11.out,format=b 12834
jhat -J-mx1024m dump11.out
最近一段时间经常使用JDK自带工具jmap和jstack来dump JVM heap和JVM 线程栈的log来分析问题,执行这两个命令当时让我最摸不着头脑的就是碰到这个问题:well-known file is not secure
eg:
上网google了一把,在stackoverflow上找到答案:http://stackoverflow.com/questions/9100149/jstack-well-known-file-is-not-secure?rq=1,大概意思是:
我们可以在机器上找到 /tmp/hsperfdata_$USER/$PID一个这样的文件,当我们执行jmap或者jstack出现上叙信息时,先检查执行该命令的用户是否和hsperfdata_$USER这个文件所属的用户一致,如果不一致,切换至成一致再执行即可。