GC参数分析以及模拟元空间内存不足分析GC日志

JVM参数分析

  1. 下面是线上配置的web类型的JVM模板
    	-Denv=pro -Dspring.profiles.active=pro -Duser.timezone=GMT+08 
    	-Dapp.id=ZTO_INTL_EXPRESS_EXP_ADMIN_WEB -Ddubbo.protocol.telnet=-ls 
    	// xms初始化堆和xmx最大堆大小设为2048M  -Xmn年轻代大小为1024M
    	-Xmx2048M -Xms2048M -Xmn1024M 
    	// Metaspace 最大值为256M
    	-XX:MaxMetaspaceSize=256M -XX:MetaspaceSize=256M
    	// 使用CMS垃圾收集器
    	-XX:+UseConcMarkSweepGC
    	// 老年代当前使用率是否达到阈值CMSInitiatingOccupancyFraction
    	-XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70
    	// 当有系统GC调用时,永久代也被包括进CMS垃圾回收的范围内。因此,通过使用这些标志,我们可以防止出现意料之外的”stop-the-world”的系统GC
    	-XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses
    	// CMS收集器默认不会对永久代进行垃圾回收。如果希望对永久代进行垃圾回收
    	-XX:+CMSClassUnloadingEnabled 
    	// 尽可能启用并行引用处理
    	-XX:+ParallelRefProcEnabled 
    	// 在 CMS GC 的 CMS-remark 阶段开始前先进行一次 Young GC,有利于减少 Young Gen 对 Old Gen 的无效引用,降低 CMS-remark 阶段的时间开销
    	-XX:+CMSScavengeBeforeRemark
    	// 输出虚拟机装入的类的信息
    	-verbose:class
    	// 当JVM发生OOM时,自动生成DUMP文件
    	-XX:+HeapDumpOnOutOfMemoryError  
    	// 表示生成dump文件的路径
    	-XX:HeapDumpPath=/data/logs/ 
    	// 记录jvm error日志
    	-XX:ErrorFile=/data/logs/hs_err_pid%p.log 
    	// GC日志文件的输出路径
    	-Xloggc:/dev/shm/gc.log
    	// 用于输出GC日志
    	-XX:+PrintGCDetails 
    	// 用于输出GC的时间戳(日期形式,例如2019-12-24T21:53:59.234+0800)
    	-XX:+PrintGCDateStamps
    	// Full GC前后打印跟踪类视图 
    	-XX:+PrintClassHistogramBeforeFullGC 
    	-XX:+PrintClassHistogramAfterFullGC 
    	-XX:+PrintCommandLineFlags 
    	// 打印每次垃圾回收前,程序未中断的执行时间
    	-XX:+PrintGCApplicationConcurrentTime 
    	// 打印应用暂停时间
    	-XX:+PrintGCApplicationStoppedTime 
    	// 打印Young GC各个年龄段的对象分布
    	-XX:+PrintTenuringDistribution 
    	// 在GC前后打印GC日志
    	-XX:+PrintHeapAtGC
    
    1.1 -XX:+PrintGCDetails 发生垃圾收集时打印详细的内存回收日志
    (1)[GC (Allocation Failure) 表示这是一次垃圾回收,括号中Allocation Failure表示gc的原因:新生代内存不足而导致新对象内存分配失败
    在这里插入图片描述
    1.2 -XX:+PrintGCDateStamps 输出GC的时间戳
    在这里插入图片描述
    1.3 -XX:+PrintClassHistogramBeforeFullGC fullGC前类的柱状图
    在这里插入图片描述
    1.4 -XX:+PrintCommandLineFlags 打印虚拟机接受到的命令行显式参数
    在这里插入图片描述
    1.5 -XX:+PrintGCApplicationConcurrentTime 两个连续安全点之间的时间
    在这里插入图片描述
    1.6 -XX:+PrintGCApplicationStoppedTime 应用程序在安全点停止的时间
    在这里插入图片描述
    1.7 -XX:+PrintTenuringDistribution 经过7次GC,新生代对象晋升到老年代,而最大允许的年龄阈值为15
    (1)通过-XX:MaxTenuringThreshold参数可以调整
    在这里插入图片描述
    1.8 -XX:+PrintHeapAtGC 每次gc(yonggc,fullgc) 都会输出gc前后堆详情(Eden区域、from区、to区、old区、Metaspace区 、Class space等) 在这里插入图片描述
  2. 相关资料
    2.1 阿里云帮助中心的《JVM参数配置说明》

JVM内存划分

在这里插入图片描述

  1. 下图是截取美团的《Java中9种常见的CMS GC问题分析与解决》
    在这里插入图片描述

  2. -Xmn1024M指定年轻代的大小,年轻代包含一个Eden和两个Survivor
    2.1 默认的,Edem : from : to = 8 : 1 : 1 ( 可以通过参数 –XX:SurvivorRatio 来设定 )
    2.2 默认的,新生代 ( Young ) 与老年代 ( Old ) 的比例的值为 1:2 ( 该值可以通过参数 –XX:NewRatio 来指定 )

  3. Young区垃圾回收叫做Minor GC;在Old区垃圾回收叫做 Major GC,有些也会叫做 Full GC,但其实这种叫法是不规范的

CMS垃圾回收机制

  1. GC的触发机制分为:周期性Old GC(被动)和主动Old GC
  2. 触发条件
    2.1 老年代使用率达到阈值 CMSInitiatingOccupancyFraction
    2.2 新生代的晋升担保失败
  3. 周期性Old GC过程
    3.1 初识标记和重新标记会导致STW
    在这里插入图片描述
    3.2 对比GC日志进行分析
    在这里插入图片描述
    在这里插入图片描述
  4. CMS的缺点
    4.1 CMS使用的是标记-清除算法,不可避免会出现垃圾碎片问题
    4.2 一般CMS的GC耗时80%都在remark阶段
    (1)-XX:+CMSScavengeBeforeRemark。在执行remark操作之前先做一次Young GC,目的在于减少年轻代对老年代的无效引用,降低remark时的开销

模拟元空间内存不足而引发的Full GC

  1. 模拟Metaspace内存溢出
    1.1 将元空间设置为10m : -XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m
public class Demo1 {
    public static void main(String[] args) {
        long count = 0L;
        while (true) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(Car.class);
            enhancer.setUseCache(false);
            enhancer.setCallback(new MethodInterceptor() {
                public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                    if (method.getName().equals("run")) {
                        System.out.println("Before run, security checking...");
                        return methodProxy.invokeSuper(o, objects);
                    } else {
                        return methodProxy.invokeSuper(o, objects);
                    }
                }
            });

            Car car = (Car) enhancer.create();
            car.run();

            System.out.println("Created " + ++count +" Car.");
        }
    }

    static class Car {
        public void run() {
            System.out.println("Car is running...");
        }
    }

    static class SafeCar extends Car{
        @Override
        public void run() {
            System.out.println("Car is running...");
            super.run();
        }
    }
}
  1. 对GC日志进行分析
    2.1 重启之后,gc日志会被覆盖
    (1)防止被覆盖,可以增加如下配置

    # GC日志输出的文件路径
    -Xloggc:/path/to/gc-%t.log
    # 开启日志文件分割
    -XX:+UseGCLogFileRotation 
    # 最多分割几个文件,超过之后从头文件开始写
    -XX:NumberOfGCLogFiles=14
    # 每个文件上限大小,超过就触发分割
    -XX:GCLogFileSize=100M
    

    在这里插入图片描述

    2.2 对GC日志进行分析,在日志进行注释分析

    // Metadata GC Threshold说明了gc发生的原因,是因为元空间内存不足够而产生扩容导致的GC
     2021-12-31T11:00:29.183+0800: 2.013: [Full GC (Metadata GC Threshold) 2021-12-31T11:00:29.183+0800: 2.014: [Class Histogram (before full gc): 
     num     #instances         #bytes  class name
    ----------------------------------------------
    省略类的柱状图
    Total       1095798       75249104
    , 0.0456603 secs]
    // [CMS: 0K->19938K(1048576K)看出在老年代内存使用为0的时候就发生了Full GC,所以可以确定不是因为老年代内存不够用而发生的gc
    2021-12-31T11:00:29.229+0800: 2.059: [CMS: 0K->3802K(102400K), 0.0361704 secs]2021-12-31T11:00:29.266+0800: 2.095: [Class Histogram (after full gc): 
     num     #instances         #bytes  class name
    ----------------------------------------------
    省略类的柱状图
    	Total         67493        3823264
    , 0.0071457 secs]
    // [Metaspace: 9888K->9888K(1058816K)] gc前后的元空间(Metaspace)内存变化
    73485K->3802K(194560K), [Metaspace: 9888K->9888K(1058816K)], 0.0892254 secs] [Times: user=0.20 sys=0.00, real=0.09 secs] 
    ........
    // 最后的拯救机会(Last ditch collection)Metaspace区中的对象依旧无法回收,也不够容纳新创建的类对象,所以JVM直接终止运行,并打印出最后的堆内存的情况
    2021-12-31T11:00:29.273+0800: 2.103: [Full GC (Last ditch collection) 2021-12-31T11:00:29.273+0800: 2.103: [Class Histogram (before full gc): 
    num     #instances         #bytes  class name
    ------------------------------------------------------
    省略类的柱状图
    Total         67493        3823264
    , 0.0072663 secs]
    2021-12-31T11:00:29.280+0800: 2.110: [CMS: 3802K->2678K(102400K), 0.0157369 secs]2021-12-31T11:00:29.295+0800: 2.126: [Class Histogram (after full gc): 
    num     #instances         #bytes  class name
    ----------------------------------------------
    省略类的柱状图
    Total         45263        2706816
    , 0.0064766 secs]
     3802K->2678K(194560K), [Metaspace: 9888K->9888K(1058816K)], 0.0296249 secs] [Times: user=0.06 sys=0.00, real=0.03 secs] 
    
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值