对《假笨说-又抓了一个导致频繁GC的鬼--数组动态扩容》实践

对《假笨说-又抓了一个导致频繁GC的鬼–数组动态扩容》实践

1、本文根据此文章进行操作,学习jvm相关的知识:假笨说-又抓了一个导致频繁GC的鬼–数组动态扩容
2、基于jdk1.7实践

1、用到的jvm参数:

  • -Xmx550M -Xms550M -Xmn200M heap堆最大550m,初始heap大小为550m,最大新生代大小为200m;
  • UseConcMarkSweepGC :This flag is needed to activate the CMS Collector in the first place. By default, HotSpot uses the Throughput Collector instead.
  • -XX:+UseCMSInitiatingOccupancyOnly :不基于垃圾收集器收集的状况来选择使用收集器,而是直接使用cms收集器
  • -XX:CMSInitiatingOccupancyFraction=80:当老年代的内存使用站80%时,触发老年代回收;
  • -XX:+PrintGC 打印gc日志
  • -XX:+PrintGCDetails 打印gc详细日志
  • -XX:+PrintGCTimeStamps :gc的时刻
  • -XX:+PrintGCApplicationStoppedTime :打印stop-the-word消耗的时间
  • -XX:+CMSScavengeBeforeRemark :

2、 程序

/**
 *-Xmx550M -Xms550M -Xmn200M    
-XX:+UseConcMarkSweepGC  
-XX:+UseCMSInitiatingOccupancyOnly 
-XX:CMSInitiatingOccupancyFraction=80
-XX:+PrintGC 
-XX:+PrintGCDetails 
-XX:+PrintGCTimeStamps
-XX:+PrintGCApplicationStoppedTime
-XX:+CMSScavengeBeforeRemark
 * @author Rail
 */
public class Main {
    public static void main(String[] args){
        System.out.println("hi");
        allocateMemory();
        try {
            Thread.sleep(1000000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private static void allocateMemory() {
        List<byte[]> list = new ArrayList<byte[]>();
        int size = 480 * 1024 * 1024; 
        System.out.println(size);
        int len = size / (20 * 1024);
        System.out.println("len = "+len);
        for(int i = 0; i < len; i++){

            byte[] bytes = new byte[20*1024];
            list.add(bytes);
            /*if(i == 23760){
                System.out.println("waiting");
                try {
                    Thread.sleep(10000000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }*/
            if(i > 15740){
                System.out.println("waiting 1s");
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(i+" "+20*(i + 1)+"kb");
        }
    }
}

3、内存分配过程

  • 每次在新生代分配20kb的内存,约8000次(160mb)后,触发parnew,因为空闲不能容纳160mb,触发老年代的分配担保,从而新生代内存为20mb,老年代为140mb;
    这里写图片描述
  • 继续分配20kb,分配16000次,新生代由20mb变为180mb
    • 触发parnew,空闲的sur不能容纳180mb,触发老年代分配担保,从而新生代由180mb变为20mb,老年代为140mb+160mb=300mb;
    • 老年代300mb触发cms,因为分配的内存在此时都是不可回收的,cms虽然执行,但是不能缩小老年代的实际使用大小。
      这里写图片描述
  • 继续分配20kb,在24000次,新生代由20mb达到180mb,

    • 按照上面的逻辑是:空闲的sur不能容纳180mb,触发老年代分配担保,因为老年代已经300mb了,最大是350mb,只能分配担保50mb,新生代由180mb减小至150mb左右,然后后续的对象分配在新生代中分配,由150mb开始,从下图打印的信息看,这样解释也行得通:
      这里写图片描述

    • 但是在gc日志中,是老年代由300mb变为350mb,然后新生代才由180mb变为110mb的。上一种说法就不成立了,那cms是可以主动的缩小新生代的大小吗?这是我未解决的疑问。
      这里写图片描述

4、jstat -gc pid 属性说明

  • S0C :survivor0的最大内存
  • S1C :survivor1的最大内存
  • S0U :survivor0的已用内存
  • S1U :survivor1的已用内存
  • EC :Eden区的最大内存
  • EU:Eden区的已用内存
  • OC:老年代的可用内存
  • OU:老年代的已用内存
  • MC:Metaspace(元空间)最大内存
  • MU :Metaspace(元空间)已用内存
  • CCSC:压缩类空间最大内存
  • CCSU:压缩类空间已用内存
  • YGC:年轻的gc次数
  • YGCT:年轻代gc时间
  • FGC:full gc次数
  • FGCT:full gc时间
  • GCT:总gc时间
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值