[转]JDK自带工具之问题排查场景示例
最近看到了大量关于java性能调优、故障排查的文章,自己也写了一篇Java调优经验谈。接着此篇文章,其实一直打算写写一些常用调优工具以及它们的惯常用法的。后来在http://java-performance.info这个站点上看到了类似的一篇博文,自我感觉很有指导意义。于是决定翻译+重组织一下此篇文章:Java server application troubleshooting using JDK tools。
引言
在Java世界中,我们的很多开发工作从编码、调试到调优都在使用GUI工具。我们经常尝试在本地构建一套和线上一样的环境从而使得问题能够重现,进而使用我们常用的工具来排查定位故障。但不幸的是,很多情况下是无法在本地重现线上问题的。例如,我们没有权限获取真实客户端提交到线上服务端的数据。
由此,很多时候都是需要远程来排查线上服务器上发生的问题。但是如果单单只有一个JRE的话,你也不可能有合适的办法来进行排查。你需要JDK或者第三方的工具。有时候使用JDK提供的工具就是最可取的方案,毕竟,在线上环境使用第三方工具有时候会牵扯到权限的问题。
一般情况下,在线上环境安装JDK发布版本可以让排查进行地更高效。建议安装使用最新的Java7/8 JDK或者构建与线上JRE匹配的一些工具(原文作者不建议安装jdk的发布版本,而是建议根据实际需求逐渐地安装其中的工具)。
问题排查场景
获取正在运行的JVM列表
为了开始排查工作,我们首先需要获取正在运行的jvm进程列表,包括进程id、命令行参数等。有时候仅仅这一步就可以定位到问题,例如,同样的app实例被重复启动在并发做同样的事情(破坏输出文件、重新打开sockets或者其他愚蠢的事情)。
使用jcmd不加任何参数即可获取jvm进程列表
25691 org.apache.catalina.startup.Bootstrap start
20730 org.apache.catalina.startup.Bootstrap start
26828 sun.tools.jcmd.JCmd
3883 org.apache.catalina.startup.Bootstrap start
使用jcmd help能够获取某个jvm进程其他可用的诊断命令。例如:
[root@test-172-16-0-34-ip ~]# jcmd 3883 help
3883:
The following commands are available:
VM.commercial_features
ManagementAgent.stop
ManagementAgent.start_local
ManagementAgent.start
Thread.print
GC.class_histogram
GC.heap_dump
GC.run_finalization
GC.run
VM.uptime
VM.flags
VM.system_properties
VM.command_line
VM.version
help
输入jcmd 可以运行一个诊断命令或者获取到参数错误信息。
[root@test-172-16-0-34-ip ~]# jcmd 3883 GC.heap_dump
3883:
java.lang.IllegalArgumentException: Missing argument for diagnostic command
通过jcmd help 你能够获取此诊断命令更多的信息。如下是GC.heap_dump命令的help。
[root@test-172-16-0-34-ip ~]# jcmd 3883 help GC.heap_dump
3883:
GC.heap_dump
Generate a HPROF format dump of the Java heap.
Impact: High: Depends on Java heap size and content. Request a full GC unless the '-all' option is specified.
Syntax : GC.heap_dump [options] <filename>
Arguments:
filename : Name of the dump file (STRING, no default value)
Options: (options must be specified using the <key> or <key>=<value> syntax)
-all : [optional] Dump all objects, including unreachable objects (BOOLEAN, false)
Java堆的DUMP
jcmd提供了输出HPROF格式的堆dump接口。运行jmcd GC.heap_dump 即可。注意这里的FILENAME是相对于运行中的jvm目录来说的,因此避免找不到dump的文件,这里推荐使用绝对路径。此外,也建议使用.hprof作为输出文件的扩展名。
在堆dump完成之后,你可以复制此文件到本地用VisualVM或者用jmc的JOverflow插件打开,进而通过分析堆的状况定位内存问题。
需要注意的两点:
还有很多可以打开hprof文件进行分析的工具:NetBeans, Elipse的MAT,jhat等等。用你最熟悉的即可。
同样可以使用jmap -dump:live,file= 来产生堆dump文件,但是官方文档标注了此工具为unsupported的。虽然我们绝大多数人都会认为JDK中unsupported的特性会永远存在,但是事实并非这样:JEP 240, JEP 241。
分析类柱状图
如果正在排查内存泄漏问题,你可能想要知道堆中某种类型的存活对象数目。例如,某一时刻某些类应该只有一个实例(单例模式),但是此类的另外一个或者多个实例却已经到了老年代,但是事实上它们不应该能够被GC roots访问到。
运行以下命令可以打印出类柱状图(同时也打印出存活对象的数目):
jcmd <PID> GC.class_histogram
jmap -histo:live <PID>
输出如下:
num #instances #bytes class name
----------------------------------------------
1: 37083 48318152 [B
2: 235781 22496784 [C
3: 103958 16069448 <constMethodKlass>
4: 482361 15435552 java.util.HashMap$Entry
5: 103958 14152480 <methodKlass>
6: 9576 11192168 <constantPoolKlass>
7: 186264 10430784 com.mysql.jdbc.ConnectionPropertiesImpl$BooleanConnectionProperty
8: 274109 8771488 java.util.Hashtable$Entry
9: 9576 7210152 <instanceKlassKlass>
10: 7972 6404256 <constantPoolCacheKlass>
11: 229637 5511288 java.lang.String
12: 48471 5428752 java.net.SocksSocketImpl
13: 21599 3859672 [Ljava.util.HashMap$Entry;
这里的以byte为单位的占用大小是浅尺寸(shallow size),并没有包括子对象的大小。其实这个事实很容易由char[]和String的统计数据注意到:这俩的实例数目是差不多的,但是char[]的占用大小要大很多,就是因为String并未包含下面的char[]的大小。
有了类柱状图信息,你就可以grep/search类的名字从而获取存活实例的数目。如果你发现某些类的实例数量比期望要大很多,你就可以做heap dump,然后用任意的heap分析工具来分析问题。
线程Dump
很多时候,应用会呈现出“卡在那里”的情形。这里有很多种卡住的状况:死锁、cpu密集运算。为了定位到问题所在需要知道线程在做什么、持有了什么锁等等。
Java中有两种锁:基于sychronized和Object.wait/notifyAll方法的原始锁以及java5引入的java.util.concurrent锁。这俩种锁的不同之处主要在于前者是限制在进入synchronized部分的地方的栈帧(stack frame)中的,并且会一直在线程dump中存在。后者却并不限制在栈帧中,你可以在一个方法中进入锁,在另一方法中解锁。因此,thread dump有时候并没有包含这些信息。尽管如此,还是应该使用thread dump来查看线程信息排查问题。
这里有三种方法可以打印应用的thread dump。
kill -3 <PID> #仅限Linux平台
jstack <PID>
jcmd <PID> Thread.print
运行Java飞行记录器(Java Flight Recorder)
上面讲到的工具都是作为快速的查看诊断工具的。如果要深入分析问题,可以选择使用内置的Java飞行记录器:Java Mission Control。
运行JFR需要三步:
1. 创建一个包含了你自己配置的JFR模板文件。运行jmc, 然后Window->Flight Recording Template Manage菜单。准备好档案后,就可以导出文件,并移动到要排查问题的环境中。
2. 由于JFR需要JDK的商业证书,这一步需要解锁jdk的商业特性。
jcmd <PID> VM.unlock_commercial_features
3. 最后你就可以启动JFR。
jcmd <PID> JFR.start name=test duration=60s settings=template.jfc filename=output.jfr
上述命令立即启动JFR并开始使用templayte.jfc的配置收集60s的JVM信息,输出到output.jfr中。
一旦记录完成之后,就可以复制.jfr文件到你的工作环境使用jmc GUI来分析。它几乎包含了排查jvm问题需要的所有信息,包括堆dump时的异常信息。
后记
本文基本上是对英文原文的翻译,主要描述了几个常见问题的排查场景。
不得不说的是,JDK自带的工具是非常强大的。用好了这些工具其实已经足以应付绝大多数的Java问题排查场景。
[转]JDK自带工具之问题排查场景示例的更多相关文章
- JDK自带工具之问题排查场景示例
		
最近看到了大量关于java性能调优.故障排查的文章,自己也写了一篇< Java调优经验谈 >.接着此篇文章,其实一直打算写写一些常用调优工具以及它们的惯常用法的.后来在http://jav ...
 - JDK自带工具keytool生成ssl证书
		
前言: 因为公司项目客户要求使用HTTPS的方式来保证数据的安全,所以木有办法研究了下怎么生成ssl证书来使用https以保证数据安全. 百度了不少资料,看到JAVA的JDK自带生成SSL证书的工具: ...
 - 利用JDK自带工具监控JVMCPU和内存指标
		
特别提示:本人博客部分有参考网络其他博客,但均是本人亲手编写过并验证通过.如发现博客有错误,请及时提出以免误导其他人,谢谢!欢迎转载,但记得标明文章出处:http://www.cnblogs.com/ ...
 - jvm性能监控(3)-jdk自带工具 jps jstack jmap
		
一.概要: jps -l 查看现有的java进程 jps -l 显示所有正在运行的java进程id jstack 查看Java线程 jstack -l pid; 做thread dump ...
 - JDK 自带工具试用(一)
		
简述: 运维监控会用到JDK的小工具 说明: 1. jps 用来查看当前运行的Java进程 我在eclipse中起了一个web 应用 或者用jps -l 可以查看的更清楚一点 jps -v 看到103 ...
 - JDK自带工具介绍
		
JDK工具一览表 工具名称 功能描述 appletviewer.exe 用于运行并浏览applet小程序. apt.exe 注解处理工具(Annotation Processing Tool),主要用 ...
 - 利用JDK自带工具keyTool生成安全证书
		
前言:说一下最近做的工作,主要利用iText给网页中生成好的html报表转化为pdf格式的文件,并且在其中加入水印,数字签名等等,这部分主要介绍安全证书的目的就是为了做数字签名部分用的. 下面利用jd ...
 - JDK自带工具列表
		
JDK是一个功能强大的Java开发套装,它不仅仅为我们提供了Java运行环境,还给开发人员提供了许多有用的开发组件(位于bin目录中,如下图所示).仅仅使用JDK,就能够解决我们在Java开发过程中遇 ...
 - JDK自带工具一览表。妈妈再也不用担心你到处去下载小软件了~~
		
原来JDK早早就给我准备好了要用到的工具..反编译,JVM性能监视.诊断. JDK(Java Development Kit)是Java程序员最核心的开发工具,没有之一. JDK是一个功能强大的Jav ...
 
随机推荐
- POJ - 3252 A - Round Numbers
			
The cows, as you know, have no fingers or thumbs and thus are unable to play Scissors, Paper, Stone' ...
 - L309  单音节词读音规则(一)-辅音字母发音规则
			
1 字母和音素不是一一对应的 2单词读音规则知识结构全图 二 15个发音不变化的辅音字母:字母发音和音素一致 b / b / by d / d / dog f / f / fish h ...
 - ESP8266上报数据到中国移动物联网平台HTTP
			
#include <HttpPacket.h> #include <ArduinoJson.h> #include <ESP8266WiFi.h> HttpPack ...
 - 记一次ios加急上架经历
			
https://developer.apple.com//contact/app-store/?topic=expedite app迭代版本上架之前一直好好的没报错,没crash,但是有一次加急上架, ...
 - centos6.6安装hadoop-2.5.0(三、完全分布式安装)
			
操作系统:centos6.6(三台服务器) 环境:selinux disabled:iptables off:java 1.8.0_131 安装包:hadoop-2.5.0.tar.gz hadoop ...
 - POJ 2234 Matches Game(Nim博弈裸题)
			
Description Here is a simple game. In this game, there are several piles of matches and two players. ...
 - js中call、apply和bind的区别
			
在JS中,这三者都是用来改变函数的this对象的指向的,他们有什么样的区别呢.在说区别之前还是先总结一下三者的相似之处:1.都是用来改变函数的this对象的指向的.2.第一个参数都是this要指向的对 ...
 - SQL注入之Sqli-labs系列第十二关
			
开始挑战第十二关(Error Based- Double quotes- String) 12点半了,不困,继续,继续,继续 先看看页面,通常的使用单引号等进行操作,看看啥么情况先 咦,出现错误信息了 ...
 - Webservice客户端动态调用服务端功能方法
			
一.发布WebService服务 方式一:在服务端生成wsdl文件,下方客户端直接引用即可 优点:针对要发布的方法生成一个wsdl文件即可,无需多余配置. 缺点:每次服务端方法发生改变都需 ...
 - php操作redis(转)
			
Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API. Redis支持的数据类型有 Stirng(字符串), Lis ...