GC日志详解以及根据gc日志优化JVM

文章目录

  • GC日志
    • 如何分析GC日志
      • 打印gc日志
      • 分析GC日志
      • 简单优化
      • 通过工具分析日志
      • ParNewGC和ConcMarkSweepGC日志
      • G1收集器(-XX:+UseG1GC) 日志
  • 相关学习路线

GC日志

对于java应用我们可以通过一些配置把程序运行过程中的gc日志全部打印出来,然后分析gc日志得到关键性指标,分析 GC原因,调优JVM参数。
打印GC日志方法,在JVM参数里增加参数

‐XX:+PrintGCDetails  
‐XX:+PrintGCTimeStamps  
‐XX:+PrintGCDateStamps  
‐Xloggc:./gc.log 

Tomcat则直接加在JAVA_OPTS变量里。

如何分析GC日志

打印gc日志

启动一个java程序,加入以上参数

java -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:./gc.log -jar application.jar

分析GC日志

下图中是截取的JVM刚启动的一部分GC日志 。
GC日志详解以及根据gc日志优化JVM_第1张图片

CommandLine flags: -XX:InitialHeapSize=198572224 -XX:MaxHeapSize=3177155584 -XX:+PrintGC -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC

我们可以看到图中第一行红框,是项目的配置参数。这里不仅配置了打印GC日志,还有相关的VM内存参数。

2019-09-30T14:57:12.993+0800: 4.615: [Full GC (Metadata GC Threshold) [PSYoungGen: 3104K->0K(200704K)] [ParOldGen: 3407K->6253K(80896K)] 6511K->6253K(281600K), [Metaspace: 20585K->20585K(1069056K)], 0.0798113 secs] [Times: user=0.16 sys=0.00, real=0.08 secs] 

第二行红框中的是在这个GC时间点发生GC之后相关GC情况。

  • 1、对于4.615 这是具体发生GC的时间点。这是时间戳是从jvm启动开始计算的,前面还有具体的发生时间日期。
  • 2、Full GC(Metadata GC Threshold)指这是一次full gc,括号里是gc的原因, PSYoungGen是年轻代的GC, ParOldGen是老年代的GC,Metaspace是元空间的GC
  • 3、 3104K->0K(200704K),这三个数字分别对应GC之前占用年轻代的大小,GC之后年轻代占用,以及整个年轻代的大 小。
  • 4、3407K->6253K(80896K),这三个数字分别对应GC之前占用老年代的大小,GC之后老年代占用,以及整个老年代的 大小。
  • 5、6511K->6253K(281600K),这三个数字分别对应GC之前占用堆内存的大小,GC之后堆内存占用,以及整个堆内存 的大小。
  • 6、20585K->20585K(1069056K),这三个数字分别对应GC之前占用元空间内存的大小,GC之后元空间内存占用,以 及整个元空间内存的大小。
  • 7、0.0798113 是该时间点GC总耗费时间。

简单优化

通过GC日志可以发现,因为Metadata GC Threshold的原因,即元空间不足导致FullGC,所以可以通过添加元空间参数来优化JVM

java -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:./gc-1.log -jar application.jar 

优化后的GC日志
GC日志详解以及根据gc日志优化JVM_第2张图片
从上图可看出,扩大了元空间后并没有Full GC出现,达到了优化目的。

通过工具分析日志

上面的这些参数,能够帮我们查看分析GC的垃圾收集情况。但是如果GC日志很多很多,成千上万行。就算你一目十行, 看完了,脑子也是一片空白。所以我们可以借助一些功能来帮助我们分析,这里推荐一个gceasy(https://gceasy.io),可以 上传gc文件,然后他会利用可视化的界面来展现GC情况。具体下图所示

GC日志详解以及根据gc日志优化JVM_第3张图片
GC日志详解以及根据gc日志优化JVM_第4张图片
上图我们可以看到年轻代,老年代,以及永久代的内存分配,和最大使用情况。
GC日志详解以及根据gc日志优化JVM_第5张图片
上图我们可以看到堆内存在GC之前和之后的变化,以及其他信息。 这个工具还提供基于机器学习的JVM智能优化建议,当然现在这个功能需要付费
GC日志详解以及根据gc日志优化JVM_第6张图片
GC日志详解以及根据gc日志优化JVM_第7张图片

ParNewGC和ConcMarkSweepGC日志

使用ParNewGC作为年轻代垃圾收集器,ConcMarkSweepGC作为老年代垃圾收集器。

-XX:+UseParNewGC -XX:+UseConcMarkSweepGC

java -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:./gc-cms.log -jar application.jar 

看下此情况的GC日志是如何的
GC日志详解以及根据gc日志优化JVM_第8张图片
执行CMS的GC,以下是CMS过程分析图,后续会对CMS的GC进行分析。
GC日志详解以及根据gc日志优化JVM_第9张图片

G1收集器(-XX:+UseG1GC) 日志

添加参数

-Xms100M -Xmx100M -XX:+UseG1GC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:D:/gclog/gc-g1.log

示例代码:

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

public class HeapTest {
    byte [] b = new byte[1024*100];//100KB

    public static void main(String[] args) throws InterruptedException {
        List<HeapTest> list = new ArrayList<HeapTest>();
        while (true){
            list.add(new HeapTest());
        }
    }
}

部分GC日志
GC日志详解以及根据gc日志优化JVM_第10张图片

相关学习路线

JAVA资深架构师成长路线->架构师筑基必备技能->JVM性能深度调优

你可能感兴趣的:(JVM,GC,JAVA)