生而自由

自由而无用的灵魂

代码触发JVM的Full GC和Young GC

之前接触到的一道题目:请写一段程序,让其运行时的表现为触发5次ygc,然后3次fgc,然后3次ygc,然后1次fgc,请给出代码以及启动参数。

找到了阿里中间件团队博客里面的两篇文章:

文章中总结的最重要的规则如下:

总结上面分析的策略,可以看到采用Parallel GC的情况下,当YGC触发时,会有两个检查:
1、在YGC执行前,min(目前新生代已使用的大小,之前平均晋升到old的大小中的较小值) > 旧生代剩余空间大小 ? 不执行YGC,直接执行Full GC : 执行YGC;
2、在YGC执行后,平均晋升到old的大小 > 旧生代剩余空间大小 ? 触发Full GC : 什么都不做。

在写代码的时候,先尝试了直接new一个大对象,但直接这么做会在Full GC之前触发一次Young GC,测试下来加了 -XX:-ScavengeBeforeFullGC 也还是会先Young GC (Full GC (Allocation Failure)之前)。

因此还是需要逐步地增加内存占用,并有目的地删除一部分引用,通过上述的两个规则来触发Full GC和Young GC。

最终的启动参数如下:

-Xms41m -Xmx41m -Xmn10m -XX:+UseParallelGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps

代码如下:

package com.spirit.test;

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

/**
 * @author Spirit
 * @since 2019-02-28
 */
public class GcTest {

    private static final int _1MB = 1024 * 1024;

    public static void main(String[] args) {
        System.out.println("0.---");

        List caches = new ArrayList();

        for (int i = 0; i < 11; i++){
            caches.add(new byte[3 * _1MB]);
        }

        System.out.println("1.---");

        caches.add(new byte[3 * _1MB]);

        caches.remove(0);
        caches.add(new byte[3 * _1MB]);


        for (int i = 0; i < 8; i++) {
            caches.remove(0);
        }
        caches.add(new byte[3 * _1MB]);

        System.out.println("2.---");

        for (int i = 0; i < 7; i++){
            caches.add(new byte[3 * _1MB]);
        }
    }
}
点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据