解读垃圾收集日志(GC日志)

目录

GC日志的重要性

GC日志相关JVM参数

通过GC日志分析堆空间总体变化

测试程序

JVM参数设置

GC日志输出

GC日志分析

查看GC日志详细信息

测试案例

测试代码

JVM参数设置

GC详细日志(经过整理)

分析YoungGC日志

分析FullGC日志

诱发GC的原因


GC日志的重要性

JVM调优的关键,无论是对于自己熟悉或者不熟悉的程序而言,做调优之前应该要读懂GC后产生的日志

GC日志相关JVM参数

bash 复制代码
# 打印GC日志(只输出垃圾收集时堆的总体变化)
-XX:+PrintGC

# 打印GC详细信息
-XX:+PrintGCDetails

# 输出GC的时间戳
-XX:+PrintGCTimeStamps
-XX:+PrintGCDateStamps

# 发生GC前后打印出堆的信息
-XX:+PrintHeapAtGC

# 指定GC日志文件的保存路径
-Xloggc:/xxx/xxx/xx.log

通过GC日志分析堆空间总体变化

测试程序

java 复制代码
package oom;

/**
 * -Xms8m -Xmx8m -XX:+PrintGC
 */
public class PrintGCLog {

    public static void main(String[] args) {
        while (true) {
            new ObjectTestPrintGC();
        }
    }

    private static class ObjectTestPrintGC {
        private int[] data = new int[128];
    }
}

JVM参数设置

bash 复制代码
-Xms8m -Xmx8m -XX:+PrintGC

GC日志输出

bash 复制代码
[GC (Allocation Failure)  2216K->1102K(7680K), 0.0005381 secs]
[GC (Allocation Failure)  2574K->1740K(7680K), 0.0005690 secs]
[GC (Allocation Failure)  3276K->1900K(7680K), 0.0006052 secs]

GC日志分析

GC类型 + GC原因 + 堆空间在GC前后的变化 + 堆总空间大小 + GC耗时

1、GC的类型

  • GC:YoungGC
  • Full GC:全面收集,收集新生代、老年代和元空间中的垃圾

2、GC的原因

  • Allocation Failure:对象分配内存失败

3、GC前,堆空间已用大小

  • 日志片段中的三次分别为:2216K、2574K、3276K

4、GC后,堆空间已用大小

  • 日志片段中的三次分别为:1102K、1740K、1900K

5、堆空间总大小

  • 7680K

6、GC所耗时长

  • 日志片段中的三次分别为:0.0005381secs、0.0005690secs、0.0006052 secs

查看GC日志详细信息

测试案例

测试代码

java 复制代码
package oom;

import java.util.ArrayList;
import java.util.List;

public class PrintGCDetailsLog {

    public static void main(String[] args) {
        List<Object> lists = new ArrayList<>();
        while (true) {
            lists.add(new PrintGCDetailObject());
        }
    }

    private static class PrintGCDetailObject {
        private int[] data = new int[1024];
    }
}

JVM参数设置

bash 复制代码
-Xms8m -Xmx8m -XX:+PrintGCDetails

GC详细日志(经过整理)

bash 复制代码
[GC (Allocation Failure) 
[PSYoungGen: 2047K->512K(2048K)] 4857K->4855K(7680K), 0.0010531 secs] 
[Times: user=0.00 sys=0.01, real=0.00 secs] 

[Full GC (Ergonomics) 
[PSYoungGen: 512K->0K(2048K)] 
[ParOldGen: 4343K->3921K(5632K)] 4855K->3921K(7680K), 
[Metaspace: 3281K->3281K(1056768K)], 0.0034813 secs] 
[Times: user=0.01 sys=0.00, real=0.01 secs] 

Heap
 PSYoungGen      total 2048K, used 134K [0x00000007bfd80000, 0x00000007c0000000, 0x00000007c0000000)
  eden space 1536K, 8% used [0x00000007bfd80000,0x00000007bfda1a30,0x00000007bff00000)
  from space 512K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007bff80000)
  to   space 512K, 0% used [0x00000007bff80000,0x00000007bff80000,0x00000007c0000000)
 ParOldGen       total 5632K, used 900K [0x00000007bf800000, 0x00000007bfd80000, 0x00000007bfd80000)
  object space 5632K, 15% used [0x00000007bf800000,0x00000007bf8e1318,0x00000007bfd80000)
 Metaspace       used 3380K, capacity 4500K, committed 4864K, reserved 1056768K
  class space    used 370K, capacity 388K, committed 512K, reserved 1048576K

分析YoungGC日志

  • GC:YoungGC
  • Allocation Failure:给对象分配内存,但内存不足
  • PSYoungGen:使用Parallel Scavenge收集器执行新生代垃圾回收
  • 2047K->512K(2048K):GC前后新生代空间已被占用大小(新生代空间总大小)
  • 4857K->4855K(7680K):GC前后堆空间已被占用大小(堆空间总大小)
  • 0.0010531 secs:本次GC的耗时

分析FullGC日志

  • Full GC:全局Full GC
  • Ergonomics:触发老年代空间分配担保机制
  • PSYoungGen:Parallel Scavenge收集器执行新生代垃圾回收
  • 512K->0K(2048K):GC前后新生代已被占用空间大小(新生代空间总大小)
  • ParOldGen:Parallel Old收集器执行老年代垃圾回收
  • 4343K->3921K(5632K):GC前后老年代已被占用空间大小(老年代空间总大小)
  • 4855K->3921K(7680K):GC前后堆空间已被占用空间大小(堆空间总大小)
  • Metaspace:回收元空间
  • 3281K->3281K(1056768K):GC前后元空间已被占用大小(元空间被分配到的总大小)
  • 0.0034813 secs:本次GC的耗时

诱发GC的原因

在JDK1.8源码中,gcCause.cpp文件中定义了运行时触发GC的原因,这里列举出其中几种原因

  • Allocation Failure:给对象分配空间时内存不足触发的GC
  • Metadata GC Threshold:元空间不足触发的GC
  • Last ditch collection:元空间分配数据失败且无法扩容时触发的GC
  • Ergonomics:使用Parallel Scavenge + Parallel Old垃圾收集器时,老年代空间分配担保触发的GC
  • Tenured Generation Full:老年代空间不足触发的GC
  • Heap Inspection Initiated GC:通过jmap命令进行堆检测时触发的GC
  • Heap Dump Initiated GC:通过jmap命令进行堆转储时触发的GC
  • System.gc():程序中手动调用方法触发GC
相关推荐
m0_515098422 小时前
如何配置Oracle分布式事务_两阶段提交与DB_DOMAIN参数
jvm·数据库·python
m0_684501982 小时前
SQL嵌套查询在ETL流程的应用_数据清洗逻辑
jvm·数据库·python
djjdjdjdjjdj2 小时前
c++ circle元编程如何使用
jvm·数据库·python
2401_871696522 小时前
如何解决Data Guard主库ORA-16038日志无法归档_强制日志传输报错排查
jvm·数据库·python
djjdjdjdjjdj2 小时前
Python Selenium怎么定位元素_By.XPATH与By.CSS_SELECTOR操作DOM节点
jvm·数据库·python
m0_493934532 小时前
C#怎么实现EF Core全局查询过滤 C#如何用HasQueryFilter配置全局过滤条件自动排除已删除数据【数据库】
jvm·数据库·python
weixin_568996062 小时前
处理大体积DBF文件导入卡顿怎么办_性能优化与分批操作
jvm·数据库·python
m0_640309302 小时前
如何处理SQL查询中的逻辑重叠:AND OR嵌套优先级
jvm·数据库·python
qq_432703662 小时前
如何快速定位SQL表中的特定行:ROWID与唯一键的应用
jvm·数据库·python