欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > 名人名企 > JVM 如何分析 GC 日志,定位 GC 性能问题?

JVM 如何分析 GC 日志,定位 GC 性能问题?

2025/4/12 20:28:37 来源:https://blog.csdn.net/nmsoftklb/article/details/146091919  浏览:    关键词:JVM 如何分析 GC 日志,定位 GC 性能问题?

GC(Garbage Collection)日志是 JVM 提供的用于记录垃圾回收过程的详细信息的文件。通过分析 GC 日志,可以了解 JVM 的内存使用情况、GC 的频率、停顿时间、回收效率等,从而帮助我们诊断和解决 GC 相关的性能问题。

1. 开启 GC 日志:

  • 常用 JVM 参数:

    • -XX:+PrintGC: 打印 GC 基本信息(已过时,但仍然可以使用)。
    • -XX:+PrintGCDetails: 打印 GC 详细信息(推荐)。
    • -XX:+PrintGCDateStamps: 在 GC 日志中打印日期和时间戳。
    • -XX:+PrintGCTimeStamps: 在 GC 日志中打印时间戳(相对于 JVM 启动时间的秒数)。
    • -Xloggc:<file>: 将 GC 日志输出到指定文件(例如 -Xloggc:gc.log)。
      • 文件轮转 (File Rotation): 可以使用 -XX:+UseGCLogFileRotation-XX:NumberOfGCLogFiles-XX:GCLogFileSize 等参数配置 GC 日志文件轮转。
    • -XX:+PrintGCApplicationStoppedTime: 打印应用程序由于 GC 导致的停顿时间。
    • -XX:+PrintGCApplicationConcurrentTime: 打印应用程序在两次 GC 之间的运行时间.
    • -XX:+PrintHeapAtGC: 在每次 GC 前后打印堆的详细信息。
    • **-XX:+PrintTenuringDistribution: ** 打印 Survivor 区中对象的年龄分布.
    • -Xlog (JDK 9+): 统一日志框架 (Unified Logging Framework). 功能更强大, 配置更灵活.
  • 示例:

    java -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:gc.log -jar myapp.jar
    
    # JDK 9+
    java -Xlog:gc*:file=gc.log:time,level,tags -jar myapp.jar
    

2. GC 日志格式 (HotSpot VM):

GC 日志的格式取决于 JVM 版本和使用的垃圾收集器,没有统一的标准格式。以下是一些常见的 GC 日志信息:

  • GC 类型:

    • Minor GC (Young GC): 新生代垃圾回收。
      • [GC[DefNew (Serial), [ParNew (ParNew), [PSYoungGen (Parallel Scavenge)
    • Major GC (Old GC): 老年代垃圾回收。
      • [Full GC (Serial Old, Parallel Old, CMS), [CMS (CMS), [G1 Old GC, [ZGC
    • Full GC: 对整个堆(包括新生代和老年代)进行垃圾回收。
      • [Full GC
  • 时间信息:

    • 时间戳: GC 发生的时间(例如,2023-10-27T10:00:00.123+0800)。
    • JVM 启动时间: GC 发生的时间(相对于 JVM 启动时间的秒数,例如 1.234s)。
  • 内存信息:

    • GC 前堆使用情况: [PSYoungGen: 100M->10M(150M)] 表示 GC 前新生代使用了 100MB,剩余 10MB,新生代总大小为 150MB。
    • GC 后堆使用情况: [ParOldGen: 200M->180M(300M)] 表示 GC 前老年代使用了 200MB,GC 后使用了 180MB,老年代总大小为 300MB。
    • 总堆使用情况: 250M->190M(450M) 表示 GC 前整个堆使用了 250MB,GC 后使用了 190MB,堆总大小为 450MB。
  • GC 耗时: 例如 0.0123456 secs (单位:秒)。

  • 其他信息:

    • 垃圾回收原因 (Allocation Failure, Ergonomics, Metadata GC Threshold, System.gc(), etc.)
    • 并发标记阶段信息 (CMS, G1)
    • Region 信息 (G1)
    • 对象年龄分布 (Tenuring Distribution)

GC 日志示例 (不同收集器):

  • Serial/Parallel GC:

    [GC (Allocation Failure) [PSYoungGen: 57344K->6688K(62464K)] 57344K->18352K(202752K), 0.0194387 secs] [Times: user=0.06 sys=0.00, real=0.02 secs]
    [Full GC (Ergonomics) [PSYoungGen: 6688K->0K(62464K)] [ParOldGen: 11664K->16366K(140288K)] 18352K->16366K(202752K), [Metaspace: 34567K->34567K(1081344K)], 0.1019658 secs] [Times: user=0.31 sys=0.04, real=0.11 secs]
    
  • CMS:

    [GC (CMS Initial Mark) [1 CMS-initial-mark: 16366K(140288K)] 18704K(202752K), 0.0008393 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
    [CMS-concurrent-mark-start]
    [CMS-concurrent-mark: 0.005/0.005 secs] [Times: user=0.02 sys=0.00, real=0.01 secs]
    [CMS-concurrent-preclean-start]
    [CMS-concurrent-preclean: 0.001/0.001 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
    [CMS-concurrent-abortable-preclean-start]
    [CMS-concurrent-abortable-preclean: 0.005/0.159 secs] [Times: user=0.29 sys=0.03, real=0.16 secs]
    [GC (CMS Final Remark) [YG occupancy: 21947 K (62464 K)]2023-10-27T16:22:32.864+0800: 3.886: [Rescan (parallel) , 0.0176854 secs]2023-10-27T16:22:32.882+0800: 3.903: [weak refs processing, 0.0000398 secs]2023-10-27T16:22:32.882+0800: 3.903: [class unloading, 0.0042382 secs]2023-10-27T16:22:32.886+0800: 3.908: [scrub symbol table, 0.0053587 secs]2023-10-27T16:22:32.892+0800: 3.913: [scrub string table, 0.0004727 secs][1 CMS-remark: 16366K(140288K)] 38313K(202752K), 0.0298176 secs] [Times: user=0.09 sys=0.00, real=0.03 secs]
    [CMS-concurrent-sweep-start]
    [CMS-concurrent-sweep: 0.013/0.013 secs] [Times: user=0.03 sys=0.00, real=0.01 secs]
    [CMS-concurrent-reset-start]
    [CMS-concurrent-reset: 0.001/0.001 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
  • G1:

    [GC pause (G1 Evacuation Pause) (young) (initial-mark), 0.0017932 secs][Parallel Time: 1.4 ms, GC Workers: 8]...[Eden: 128.0M(128.0M)->0.0B(112.0M) Survivors: 0.0B->16.0M Heap: 128.0M(2048.0M)->42.1M(2048.0M)][Times: user=0.01 sys=0.00, real=0.00 secs]
    [GC concurrent-root-region-scan-start]
    ...
    [GC pause (G1 Evacuation Pause) (young) (to-space exhausted), 0.0042688 secs][Parallel Time: 3.8 ms, GC Workers: 8]...[Eden: 0.0B(112.0M)->0.0B(112.0M) Survivors: 16.0M->16.0M Heap: 177.1M(2048.0M)->162.4M(2048.0M)][Times: user=0.02 sys=0.00, real=0.01 secs]
    [GC pause (G1 Evacuation Pause) (mixed), 0.0026325 secs]...[Eden: 0.0B(112.0M)->0.0B(128.0M) Survivors: 16.0M->0.0B Heap: 208.4M(2048.0M)->194.1M(2048.0M)][Times: user=0.01 sys=0.00, real=0.00 secs]
    [GC cleanup 194M->194M(2048M), 0.0004077 secs][Times: user=0.00 sys=0.00, real=0.00 secs]
    

3. 分析 GC 日志:

  • 关注点:
    • GC 频率: GC 发生的频率是否过高。
    • GC 停顿时间: 每次 GC 暂停了多长时间 (STW)。
    • GC 类型: 是 Minor GC、Major GC 还是 Full GC。
    • 内存使用情况: GC 前后堆内存、新生代、老年代的使用情况。
    • 垃圾回收原因: 了解触发 GC 的原因。
    • 对象年龄分布: (如果开启了 -XX:+PrintTenuringDistribution) 查看对象在 Survivor 区的年龄分布, 了解对象晋升老年代的情况.
  • 分析方法:
    • 手动分析: 阅读 GC 日志,理解每一行的含义,找出潜在的问题。
    • 使用工具分析:
      • GCViewer: 一个开源的 GC 日志可视化分析工具。
      • gceasy.io: 一个在线的 GC 日志分析工具。
      • GChisto: 一个命令行 GC 日志分析工具。
      • VisualVM, JProfiler 等: 可以实时监控GC情况.
    • 关键指标:
      • 吞吐量: 应用程序运行时间占总时间的比例(越高越好)。
      • 停顿时间: GC 导致的应用程序暂停时间(越低越好)。
      • GC 频率: GC 发生的频率(越低越好,但也要避免停顿时间过长)。
      • 内存占用: 应用程序使用的内存量。

4. 常见 GC 问题及原因:

  • 频繁 Minor GC:

    • 原因:
      • 对象分配速率过高。
      • 新生代空间不足。
    • 解决方案:
      • 优化代码,减少对象创建。
      • 增大新生代空间 (-Xmn)。
      • 调整 Eden 区和 Survivor 区的比例 (-XX:SurvivorRatio)。
  • 频繁 Full GC:

    • 原因:
      • 老年代空间不足。
      • 方法区/元空间不足。
      • 大对象过多。
      • 内存泄漏。
      • 显式调用 System.gc()
    • 解决方案:
      • 增大堆内存 (-Xmx)。
      • 增大方法区/元空间 (-XX:MaxMetaspaceSize)。
      • 避免创建过大的对象。
      • 使用分析工具 (例如,MAT) 查找内存泄漏。
      • 禁用 System.gc() 调用 (-XX:+DisableExplicitGC)。
      • 选择合适的垃圾回收器(例如,G1、CMS)。
      • 调整垃圾回收器参数。
  • GC 停顿时间过长:

    • 原因:
      • 堆内存过大。
      • 垃圾回收器选择不当。
      • 垃圾回收参数设置不合理。
    • 解决方案:
      • 选择合适的垃圾回收器(例如,G1、CMS、ZGC)。
      • 调整垃圾回收器参数(例如,-XX:MaxGCPauseMillis-XX:CMSInitiatingOccupancyFraction)。
      • 优化代码,减少对象创建。
      • 使用并发垃圾回收器。

总结:

分析 GC 日志是 JVM 调优的重要环节。通过分析 GC 日志,可以了解 JVM 的内存使用情况、GC 的频率、停顿时间、回收效率等,从而找出潜在的性能问题,并进行相应的优化。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词