聊一聊GC日志,线程转储和堆转储

Posted by Jeremy Song on 2021-07-24
Estimated Reading Time 7 Minutes
Words 1.6k In Total
Viewed Times

一般情况下,我们可以通过Java虚拟机(Java Virtual Machine,JVM)生成的如下三个关键文件来进行产品的性能优化,或者是解决一些生产问题。

  • 垃圾收集(Garbage collection,GC)日志
  • 线程转储(Thread dump)
  • 堆转储(Heap dump)

那么这三个文件都是什么呢?别傻傻分不清楚了,下面就来对比一下这三个文件都是干啥的。

介些都是些啥东东

GC日志

GC日志包含了垃圾收集事件的相关信息,比如:“发生了多少次GC事件”,“这些各自是什么类型的GC事件(比如,年轻代GC或完整GC)”,“每个GC事件将应用暂停了多长时间”,“每个GC事件回收了多少对象”。

线程转储

线程转储是一个运行中的应用在某一个时刻的所有线程的快照,它包含了应用中的每一个线程的所有信息。比如:线程状态,线程ID,原生ID,线程名称,线程栈信息,线程优先级。

堆转储

堆转储是一个运行中的应用在某一个时刻的内存快照,它同样也包含了很多信息。比如:内存中都有那些对象,这些对象的当前值,对象的大小,对象的引用关系。

来!出来亮个相

是骡子是马拉出来遛遛!下面各举个例子先让大家看看这几个东东都长什么样子,消除一下神秘感。

GC日志

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2021-04-01T12:32:24.398+0800: 0.356: [GC pause (G1 Evacuation Pause) (young), 0.0215287 secs]
[Parallel Time: 20.0 ms, GC Workers: 8]
[GC Worker Start (ms): Min: 355.9, Avg: 356.3, Max: 358.4, Diff: 2.4]
[Ext Root Scanning (ms): Min: 0.0, Avg: 6.4, Max: 16.7, Diff: 16.7, Sum: 51.4]
[Update RS (ms): Min: 0.0, Avg: 1.0, Max: 2.5, Diff: 2.5, Sum: 8.2]
[Processed Buffers: Min: 0, Avg: 1.1, Max: 5, Diff: 5, Sum: 9]
[Scan RS (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
[Code Root Scanning (ms): Min: 0.0, Avg: 0.0, Max: 0.1, Diff: 0.1, Sum: 0.1]
[Object Copy (ms): Min: 2.9, Avg: 11.9, Max: 17.5, Diff: 14.6, Sum: 95.3]
[Termination (ms): Min: 0.0, Avg: 0.1, Max: 0.2, Diff: 0.2, Sum: 0.9]
[Termination Attempts: Min: 1, Avg: 2.5, Max: 5, Diff: 4, Sum: 20]
[GC Worker Other (ms): Min: 0.0, Avg: 0.1, Max: 0.1, Diff: 0.1, Sum: 0.5]
[GC Worker Total (ms): Min: 17.5, Avg: 19.6, Max: 19.9, Diff: 2.4, Sum: 156.5]
[GC Worker End (ms): Min: 375.8, Avg: 375.9, Max: 375.9, Diff: 0.1]
[Code Root Fixup: 0.0 ms]
[Code Root Purge: 0.0 ms]
[Clear CT: 0.5 ms]
[Other: 1.0 ms]
[Choose CSet: 0.0 ms]
[Ref Proc: 0.4 ms]
[Ref Enq: 0.0 ms]
[Redirty Cards: 0.4 ms]
[Humongous Register: 0.0 ms]
[Humongous Reclaim: 0.0 ms]
[Free CSet: 0.0 ms]
[Eden: 12.0M(12.0M)->0.0B(14.0M) Survivors: 0.0B->2048.0K Heap: 12.6M(252.0M)->7848.3K(252.0M)]
[Times: user=0.08 sys=0.00, real=0.02 secs]

线程转储

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
"HeavyThread" #11 prio=5 os_prio=0 tid=0x000001885e78f000 nid=0x2e3c runnable [0x0000001b443fe000]
java.lang.Thread.State: RUNNABLE
at java.io.FileOutputStream.writeBytes(Native Method)
at java.io.FileOutputStream.write(Unknown Source)
at java.io.BufferedOutputStream.flushBuffer(Unknown Source)
at java.io.BufferedOutputStream.flush(Unknown Source)
- locked <0x00000006c1407098> (a java.io.BufferedOutputStream)
at java.io.PrintStream.write(Unknown Source)
- locked <0x00000006c1406a90> (a java.io.PrintStream)
at sun.nio.cs.StreamEncoder.writeBytes(Unknown Source)
at sun.nio.cs.StreamEncoder.implFlushBuffer(Unknown Source)
at sun.nio.cs.StreamEncoder.flushBuffer(Unknown Source)
- locked <0x00000006c14201b0> (a java.io.OutputStreamWriter)
at java.io.OutputStreamWriter.flushBuffer(Unknown Source)
at java.io.PrintStream.newLine(Unknown Source)
- eliminated <0x00000006c1406a90> (a java.io.PrintStream)
at java.io.PrintStream.println(Unknown Source)
- locked <0x00000006c1406a90> (a java.io.PrintStream)
at com.jeremy.tech.lab.CPULoadTester$HeavyLoadTask.run(CPULoadTester.java:13)
at java.lang.Thread.run(Unknown Source)

堆转储

堆转储文件为二进制格式,并且通常较大,这里就不举例子了。 除此之外,堆转储格式相关文档少的可怜。 因此,我们必须借助堆转储分析工具来分析和理解这玩意。

这些文件都用在什么场景

GC日志

垃圾收集日志用于优化GC暂停时间,用于确定应用程序的最佳内存大小,还用于解决与内存相关的问题。

线程转储

线程转储主要用于解决生产问题,例如CPU尖峰,应用程序无响应,响应时间差,线程挂起,内存消耗高。

内存转储

堆转储主要用于解决与内存相关的OutOfMemoryError问题。

我怎么获取这些文件呢

GC日志

使用如下的JVM参数可以生成垃圾收集日志:

  • java 8及以前版本
1
2
3
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-Xloggc:<file-path>
  • java 9及以后版本
1
-Xlog:gc*:file=<file-path>

注:<file-path>为垃圾收集日志的生成文件路径

线程转储

线程转储捕获的方法比较多,后面有时间了再展开说说,这里说个一般方法。通常情况下,我们使用 jstack 工具来获取线程转储, jstackJDK_HOME\bin 目录下。线程转储文件可以用如下方式获取:

1
jstack -l <pid> > <file-path>

注:<pid>为应用进程号;<file-path>为线程转储文件生成的文件路径

堆转储

同样,堆转储获取的方法也比较多,后面有空再细说。通常情况下,我们使用 jmap 工具来获取堆转储, jmapJDK_HOME/bin 目录下。获取堆转储文件用以下方法即可:

1
jmap -dump:format=b,file=<file-path> <pid>

注:<pid>为应用进程号;<file-path>为堆转储文件生成的文件路径

分析工具

GC日志

线程转储

堆转储

最后

本篇主要是一个偏科普性质的文章,从几个不同的出发点比较了GC日志、线程转储文件、堆转储文件。平时在性能优化和问题处理的过程中必然少不了会用到这些。当然在分析的过程中的除过使用上面列出来的工具之外,还是需要您具备一定程度的JVM知识,要不然工具跑完之后也看不出来个所以然。

最好的办法是自己动手实践一下,从上面列出来的工具中找一个自己最顺手的出来,后面就会事半功倍!


欢迎关注我的公众号 须弥零一,跟我一起学习IT知识。


如果您喜欢此博客或发现它对您有用,则欢迎对此发表评论。 也欢迎您共享此博客,以便更多人可以参与。 如果博客中使用的图像侵犯了您的版权,请与作者联系以将其删除。 谢谢 !