[转]JDK自带工具之问题排查场景示例

Java应用故障排查
本文介绍如何使用JDK自带工具进行Java应用性能调优与故障排查,包括获取运行中JVM列表、生成堆dump、分析类柱状图及线程dump等操作。

最近看到了大量关于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问题排查场景。

转载于:https://www.cnblogs.com/atai/p/8206584.html

<think>嗯,用户想了解JDK自带的监控工具和功能的使用指南。这个问题很实用,尤其是对Java开发者来说,掌握这些工具对于性能调优和问题排查非常重要。从用户的问题来看,ta可能是个Java开发者或运维人员,正在寻找JDK内置工具的完整参考。用户没有具体说明使用场景,但提到了"使用指南",说明需要实操性强的指导而非概念介绍。我注意到引用内容很丰富,涵盖jps、jstat、jmap等命令行工具和JConsole、VisualVM等图形工具,还包含JFR高级功能,这些都需要系统化整理。首先考虑按工具类型分层介绍:命令行工具和GUI工具分开说明更清晰。命令行工具重点讲jps(进程查看)、jstat(GC监控)、jmap(堆分析)这些核心命令,每个都要给出具体使用示例和输出解读,比如jstat-gcutil展示GC利用率百分比的含义。GUI部分则强调JConsole的实时监控能力和VisualVM的插件扩展性。特别要注意JFR(JavaFlightRecorder)这部分,引用[3]提到它是生产环境分析神器,但很多开发者不熟悉。需要说明如何用jcmd启动记录(比如jcmd<pid>JFR.startduration=60s),以及用JMC分析结果的方法。安全方面要提醒用户,远程监控时注意JMX端口的安全配置。用户可能遇到的痛点包括:如何快速定位内存泄漏?怎样监控GC频率是否正常?所以考虑在最后补充典型应用场景,比如用jmap+MAT分析OOM,用jstack查死锁等。这些实操案例能让指南更落地。还要注意引用标注的规范性。比如讲解jconsole时,引用[1]提到它支持远程监控,这个功能需要标注来源。类似地,介绍jcmd的多功能特性时引用[4]的内容也要标注。最后考虑设计相关问题:用户看完指南后可能想了解工具选择策略(比如生产环境推荐用JFR),或者具体问题排查流程(线程阻塞如何分析),这些问题能帮助ta深入实践。需要确保每个问题都能在指南基础上延伸思考。</think>以下是JDK自带的监控工具和功能使用指南,结合命令行与图形化工具进行分类说明: --- ### **一、命令行工具** #### 1. **jps(JVM Process Status)** **作用**:列出当前系统的Java进程及其PID。 **命令**: ```bash jps -l # 显示完整主类名 jps -v # 显示JVM启动参数 ``` #### 2. **jstat(JVM Statistics Monitoring)** **作用**:实时监控GC、类加载、JIT编译等数据。 **常用命令**: ```bash jstat -gcutil <pid> 1000 5 # 每1秒输出1次GC统计,共5次 ``` **输出关键字段**: - `YGC/YGCT`:Young GC次数/耗时 - `FGC/FGCT`:Full GC次数/耗时 - `GCT`:总GC耗时 #### 3. **jmap(Memory Map)** **作用**:生成堆内存快照,分析内存分布。 **常用命令**: ```bash jmap -heap <pid> # 显示堆概要信息 jmap -dump:format=b,file=heap.hprof <pid> # 导出堆快照 ``` #### 4. **jstack(Stack Trace)** **作用**:捕获线程堆栈信息,排查死锁/阻塞。 **命令**: ```bash jstack -l <pid> > thread_dump.txt # 输出线程快照 ``` #### 5. **jcmd(多功能诊断)** **作用**:集成式命令,支持JFR、堆储等高级功能[^4]。 **示例**: ```bash jcmd <pid> VM.flags # 查看JVM参数 jcmd <pid> GC.heap_info # 显示堆信息 jcmd <pid> JFR.start duration=60s filename=recording.jfr # 启动JFR记录 ``` --- ### **二、图形化工具** #### 1. **JConsole** **作用**:可视化监控CPU、内存、线程、MBean等[^1]。 **启动方式**: ```bash jconsole # 自动检测本地Java进程 ``` **核心功能**: - 内存页:实时堆/非堆内存图表 - 线程页:监视死锁和线程状态 - MBean页:管理JVM配置 #### 2. **VisualVM** **作用**:集成性能分析、堆储解析、BTrace动态追踪[^3]。 **启动**: ```bash jvisualvm ``` **进阶操作**: - **安装插件**:工具 → 插件 → 安装"Visual GC"(实时GC可视化) - **分析堆快照**:文件 → 装入 → 选择`.hprof`文件 - **远程监控**:右键"远程" → 添加JMX连接(需目标JVM启用JMX) #### 3. **Java Mission Control(JMC)** **作用**:深度分析JFR记录文件,定位性能瓶颈[^3]。 **使用流程**: 1. 生成JFR记录: ```bash jcmd <pid> JFR.start name=MyRecording duration=120s filename=myrec.jfr ``` 2. 用JMC分析: ```bash jmc # 打开JMC → 文件 → 打开 → 选择.jfr文件 ``` **关键视图**: - **内存页**:对象分配热点与GC暂停 - **代码页**:方法执行时间排名 - **线程页**:线程阻塞事件分析 --- ### **三、典型应用场景** 1. **内存泄漏分析** - 步骤:`jmap -dump`导出堆 → VisualVM分析对象保留链 2. **GC性能调优** - 工具:`jstat -gcutil`监控GC频率 → JConsole观察内存趋势 3. **死锁排查** - 方法:`jstack`捕获线程快照 → 搜索"deadlock"关键字 4. **生产环境诊断** - 方案:JFR低开销记录 → JMC离线分析性能瓶颈[^3] --- ### **安全提醒** - **远程监控需配置JMX**: 启动JVM时添加参数: ```bash -Dcom.sun.management.jmxremote.port=9090 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false ``` - **敏感操作权限**:`jmap`和`jstack`需与目标JVM相同用户权限执行。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值