文章目录
- 一. 各日志概述
- 1. Garbage Collection Log - 找到GC规律
- 2. 线程转储(Thread dump) - 分析(快照)线程状态
- 3. 堆转储(Heap dump) - APP某刻内存使用全貌
- 二. 命令
- 1. 程序的gc日志
- 2. 线程转储
- 3. 堆转储
概述
在 Java 虚拟机中,(GC) Garbage collection log 垃圾收集日志、 Thread Dump 线程转储、( 储:代表存储到文件)和Heap Dump 堆转储用于分析
应用程序的性能问题
和内存使用情况
,通过分析这些文件我们能够找到程序性能瓶颈或给应用程序设定合适的内存。
本文关键词:
- OOM的定位
- 分析APP GC特性
- APP内存使用分布
- 某个线程状态ing
一. 各日志概述
1. Garbage Collection Log - 找到GC规律
什么是 GC Log?
GC 日志包含垃圾收集事件的相关信息。它将指示运行了多少 GC 事件、它们是什么类型的 GC 事件(即 Young GC 或 Full GC)、每个 GC 事件暂停应用程序的时间、每个 GC 事件回收了多少对象。
分析GC 日志能查看出什么问题 ?
GC的作用是回收不再使用的内存,以便程序有足够的内存继续运行。垃圾收集日志用于研究应用程序的 GC 和内存性能。它用于优化 GC 暂停时间,用于确定
应用程序的最佳内存大小
。
- GC 活动频率:观察 GC 日志可以了解到各类型 GC 活动(例如 Minor GC、Major GC、Full GC)的发生频率和持续时间。
频繁的 GC 活动可能会导致应用程序的性能下降
,可以通过如下思路调优:
合理配置堆内存大小
减少对象的引用链
优化大对象的处理(例如手动管理内存或者使用专门的内存管理库)
- GC 效率:GC 日志中会记录每次 GC 活动的耗时和效率,包括停顿时间(Pause Time)、吞吐量(Throughput)等指标。通过分析这些指标,可以评估 GC 的性能,并针对性地调整 GC 策略和参数。
- GC 异常:GC 日志中还会记录一些异常情况,如 OutOfMemoryError、Metaspace OOM 等。这些异常可能会导致应用程序的崩溃或者异常终止,需要及时排查和处理。
2. 线程转储(Thread dump) - 分析(快照)线程状态
什么是 Thread dump?
线程转储是应用程序中在某个时间点上运行的
所有线程
的快照。它包含应用程序中每个线程的所有信息
,例如: 线程状态、线程 Id、本机 Id、线程名称、堆栈跟踪、优先级。
线程转储文件能解决什么问题?
线程转储文件主要用于排除生产问题,例如
CPU 峰值
、应用程序中的无响应性、响应时间差
、线程挂起
、高内存消耗
。具体地:
- 死锁(Deadlock):线程转储文件可以帮助确定是否存在死锁,并提供导致死锁的线程及其堆栈跟踪信息,有助于识别和解决死锁问题。
- 线程阻塞(Thread Block):可以确定哪些线程处于阻塞状态以及造成阻塞的原因,帮助排查应用程序中的线程阻塞问题。
- 性能问题:可以发现线程争用、长时间阻塞等,有助于优化应用程序的性能。
- 线程间通信问题:可能存在的线程间通信问题,如竞争条件、资源争用等。
3. 堆转储(Heap dump) - APP某刻内存使用全貌
什么是堆转储?
是指将 Java 虚拟机(JVM)中的堆内存中的对象信息以文件形式保存下来的过程,是某个时间的快照。堆转储文件包含了当前 JVM 堆中所有对象的详细信息,包括对象类型、大小、引用关系等。
分析堆转储能解决什么问题?
- 内存泄漏(Memory Leak)根源:可以识别出
未被释放的对象
(内存泄漏)占用了过多的内存空间,导致堆内存持续增长。通过定位哪些对象占用了大量内存以及它们的引用链,可以找出造成内存泄漏的根源。- 内存溢出(Out of Memory)
- 内存碎片化(Fragmentation):可以观察到堆内存的分配情况,包括对象的分布和内存碎片化程度。这有助于评估堆内存的使用效率,并采取措施减少内存碎片化,提高内存分配的效率。
- 性能瓶颈:可以识别出
占用大量内存的对象类型和方法调用
、频繁创建临时对象的代码段
进而有助于找出性能瓶颈。
二. 命令
1. 程序的gc日志
#打印GC详情信息
-XX:+PrintGCDetails
#打印GC时间戳
-XX:+PrintGCDateStamps
#打印触发GC原因信息
-XX:+PrintGCCause
#日志存放路径
-Xloggc:d:/gslog/qms/gc-%t.log
#开启日志文件分隔
-XX:+UseGCLogFileRotation
#最多分割几个文件,超过之后从头开始写
-XX:NumberOfGCLogFiles=5
#每个文件大小
-XX:GCLogFileSize=20M
nohup java -Xmx1024m -Xms1024m -XX:+UseG1GC -XX:+DisableExplicitGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -XX:+PrintGCCause -Xloggc:d:/gslog/qms/gc-%t.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=50M -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${D:\gslog\oomlog} -jar xxx.jar &
日志说明
分析工具一:gceasy:https://gceasy.ycrash.cn/gc-dashboard.jsp
分析工具二:GCviewer:https://github.com/chewiebug/GCViewer/releases
“Summary(摘要)” 中比较有用的是:
- “Throughput”(吞吐量百分比),吞吐量显示了有效工作的时间比例,剩下的部分就是 GC 的消耗
- “Number of GC pauses”(GC 暂停的次数)
- “Number of full GC pauses”(Full GC 暂停的次数)
以上示例中的吞吐量为 13.03%。这意味着有 86.97% 的 CPU 时间用在了 GC 上面。很明显系统所面临的情况很糟糕——宝贵的 CPU 时间没有用于执行实际工作,而是在试图清理垃圾。原因也很简单,我们只给程序分配了 512MB 堆内存。
其中“Pause”展示了 GC 暂停的总时间,平均值,最小值和最大值。这些统计可以很快判断出暂停时间是否过长。
如图我们可以得出明确的信息:累计暂停时间为 26.89秒(占总运行时间的98.9%),GC 暂停的总次数为 599 次,这在 30 秒的总运行时间里那不是一般的高。
一般来说,图像化信息能迅速揭示以下症状:
- 低吞吐量:当应用的吞吐量下降到不能容忍的地步时,用于真正的业务处理的有效时间就大量减少。按照经验,低于90% 的有效时间就值得警惕了,可能需要好好优化下 GC。
- 单次 GC 的暂停时间过长:只要有一次 GC停顿时间过长,就会影响程序的延迟指标。例如,延迟需求规定必须在 1000ms 以内完成交易,那就不能容忍任何一次GC暂停超过 1000毫秒。
- 堆内存使用率过高:
如果老年代空间在 Full GC之后仍然接近全满,程序性能就会大幅降低
,可能是资源不足或者内存泄漏。这种症状会对吞吐量产生严重影响。
参考:
GC 日志解读与分析(番外篇可视化工具)
2. 线程转储
jstack -l 10414 > threadDump.log
具体使用见我的文章:Thread Dump分析方法
3. 堆转储
jmap -dump:file=<file_name> <pid>