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

须弥零一

共 5222字,需浏览 11分钟

 ·

2021-04-02 15:59

须弥零一

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

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

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

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

介些都是些啥东东

GC日志

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

线程转储

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

堆转储

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

来!出来亮个相

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

GC日志

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] 

线程转储

"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及以前版本

-XX:+PrintGCDetails-XX:+PrintGCDateStamps-Xloggc:<file-path>

java 9及以后版本

-Xlog:gc*:file=<file-path>

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

线程转储

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

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

堆转储

同样,堆转储获取的方法也比较多,后面有空再细说。通常情况下,我们使用 jmap 工具来获取堆转储, jmap 在 JDK_HOME/bin 目录下。获取堆转储文件用以下方法即可:
jmap -dump:format=b,file=<file-path> <pid>

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

分析工具

GC日志

Gceasy (https://gceasy.io/)IBM GC & Memory visualizer (https://www.ibm.com/support/pages/java-sdk-monitoring-and-post-mortem)HP Jmeter (https://myenterpriselicense.hpe.com/cwp-ui/free-software/HPJMETER)Google Garbage Cat (https://code.google.com/archive/a/eclipselabs.org/p/garbagecat)

线程转储

fastThread (https://fastthread.io/)Samurai (https://github.com/yusuke/samurai)IBM Thread & Monitor analyzer (https://www.ibm.com/support/pages/java-sdk-monitoring-and-post-mortem)Visual VM (https://visualvm.github.io/)

堆转储

Eclipse MAT (https://www.eclipse.org/mat/)HeapHero (https://heaphero.io/)JVisualVM (https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jvisualvm.html)

最后

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



欢迎关注我的公众号“须弥零一”,原创技术文章第一时间推送。


浏览 110
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报