1. 介绍
在JAVA的世界里,我们通常喜欢用熟悉的工具在本地环境去解决线上生产服务中遇到的问题。不幸的是,由于各种原因并不是所有问题都能复现. 比如你可能并不会真正的访问到你的线上服务产生的数据。
本文将介绍一些JDK 的工具和第三方的工具类帮助你解决线上环境的应用故障问题
2. 故障解决场景
2.1. 获取正在运行的 jvm 列表
获取一系列的正在运行中的 JVM,他们的进程ID,运行命令参数。有时你会发现同一个应用会有两个或者多个实例在做同样的事情
无参执行 jcmd 命令,将会输出正在运行的 JVM 列表:
> jcmd
25377 sun.tools.jcmd.JCmd
25293
25358 org.jetbrains.idea.maven.server.RemoteMavenServer
可以通过 jcmd help 命令看到对应的 JVM 可用的命令
>jcmd 25358 help
25358:
The following commands are available:
VM.native_memory
ManagementAgent.stop
ManagementAgent.start_local
ManagementAgent.start
GC.rotate_log
Thread.print
GC.class_stats
GC.class_histogram
GC.heap_dump
GC.run_finalization
GC.run
VM.uptime
VM.flags
VM.system_properties
VM.command_line
VM.version
helpFor more information about a specific command use 'help <command>'.
输入 jcmd <PID> 具体命令
> jcmd 25358 GC.heap_dump
25358:
java.lang.IllegalArgumentException: The argument 'filename' is mandatory.
jcmd <PID> help GC.heap_dump 获得该命令的详细参数信息
>jcmd 25358 help GC.heap_dump
25358:
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.
Permission: java.lang.management.ManagementPermission(monitor)
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)
2.2. 生成内存快照
jcmd 为生成 HPROF 内存快照提供了一个便利的接口. 仅仅执行 jcmd GC.heap_dump 命令 . 注意这个文件需要你指定绝对路径才会放到你想放的地方,最好文件以 .hprof 为后缀名结尾。
在一个内存快照生成完之后,可以用 VisualVM(JDK内置工具) 打开,并且可以用它来分析堆栈内存等问题。
1.还有一些其他的稳定的工具可以处理分析 hprof 文件, NetBeans, Eclipse Memory Analyzer, YourKit 等,多多尝试,找到一个最适合自己的
2. 也可以使用 jmap -dump:live,file= 来生成内存堆栈快照.但是它的问题是没有官方文档的支持。
2.3. 分析类分布图
如果你想知道哪里发生了内存泄漏,可能只需要在内存堆里面找到某种类型的一些类。
用jcmd <PID> 输出类的分布:
jcmd 25358 GC.class_histogram
jmap -histo:live
下面是 jcmd GC.class_histogram 命令的部分输出内容
25358:
num #instances #bytes class name
----------------------------------------------
1: 10682 1368104 [C
2: 923 814744 [B
3: 1584 619512 [I
4: 3206 354456 java.lang.Class
5: 10605 254520 java.lang.String
6: 4352 174080 org.apache.lucene.index.FreqProxTermsWriter$PostingList
7: 2441 152400 [Ljava.lang.Object;
8: 4382 140224 java.util.concurrent.ConcurrentHashMap$Node
9: 2783 111320 java.util.LinkedHashMap$Entry
10: 1028 98264 [Ljava.util.HashMap$Node;
11: 2905 92960 java.util.HashMap$Node
12: 3825 61200 java.lang.Object
13: 136 58208 [Lorg.apache.lucene.index.RawPostingList;
14: 549 48312 java.lang.reflect.Method
15: 40 41376 [Ljava.util.concurrent.ConcurrentHashMap$Node;
16: 543 39096 java.lang.reflect.Field
17: 600 33600 java.util.LinkedHashMap
18: 616 29568 java.util.HashMap
19: 1079 25896 com.google.inject.TypeLiteral.....
1092: 1 16 sun.rmi.transport.proxy.RMIDirectSocketFactory
1093: 1 16 sun.rmi.transport.tcp.TCPChannel$1
1094: 1 16 sun.rmi.transport.tcp.TCPTransport$1
1095: 1 16 sun.util.calendar.Gregorian
1096: 1 16 sun.util.locale.provider.AuxLocaleProviderAdapter$NullProvider
1097: 1 16 sun.util.locale.provider.CalendarDataUtility$CalendarWeekParameterGetter
1098: 1 16 sun.util.locale.provider.SPILocaleProviderAdapter
1099: 1 16 sun.util.resources.LocaleData
1100: 1 16 sun.util.resources.LocaleData$LocaleDataResourceBundleControl
Total 76067 5282688
注意上面显示的数字仅仅是该对象 – 不包含任何子对象.
可以用 grep 命令查找你想看的对象的数量,如果该对象的数量超出了正常范围,就可以生成一个 内存快照,用内存分析工具来分析它。
2.4. 生成线程快照
有时 java 应用会出现假死的状况,诱发假死的原因有很多种:死锁,磁盘IO过高 或者一个非常低效的算法。当假死情况发生时,需要知道应用的线程执行情况,每个线程都维持了哪些锁。
可以在任何系统上执行 jstack 查看 当前线程的运行快照
jstack -l
Found one Java-level deadlock:
=============================
"Thread-1":
waiting to lock monitor 0x00007fa2f7813348 (object 0x000000079596c068, a java.lang.Object),
which is held by "Thread-0"
"Thread-0":
waiting to lock monitor 0x00007fa2f88ceca8 (object 0x000000079596c078, a java.lang.Object),
which is held by "Thread-1"Java stack information for the threads listed above:
===================================================
"Thread-1":
at com.sidepro.utils.DeadLockclass.run(JStackDemo.java:47)
- waiting to lock <0x000000079596c068> (a java.lang.Object)
- locked <0x000000079596c078> (a java.lang.Object)
at java.lang.Thread.run(Thread.java:745)
"Thread-0":
at com.sidepro.utils.DeadLockclass.run(JStackDemo.java:34)
- waiting to lock <0x000000079596c078> (a java.lang.Object)
- locked <0x000000079596c068> (a java.lang.Object)
at java.lang.Thread.run(Thread.java:745)Found 1 deadlock.
上面所有提及的工具只适合快速排查. 对于更深层次的分析,推荐 Java Filght Recorder
翻译来源:http://java-performance.info/java-server-application-troubleshooting-using-jdk-tools/
微信扫码关注: