代码演示GC回收

JVM配置

-XX:NewSize=5m 初始新生代大小
-XX:MaxNewSize=5m 最大新生代大小
-XX:InitialHeapSize=10m 初始堆大小 等同于Xms
-XX:MaxHeapSize=10m 最大堆大小 等同于Xmx
-XX:SurvivorRatio=8 Eden区占80%
-XX:PretenureSizeThreshold=10m 大对象阈值
-XX:+UseParNewGC 新生代使用ParNew
-XX:+UseConcMarkSweepGC 老年代使用CMS
-XX:+PrintGCDetils:打印详细的gc日志
-XX:+PrintGCTimeStamps:这个参数可以打印出来每次GC发生的时间
-Xloggc:gc.log:这个参数可以设置将gc日志写入一个磁盘文件

代码

public class ParNew {
    
    

    public static void main(String[] args) {
    
    
        System.out.println("main方法压入栈帧-----");
        int size = 1024 * 1024;
        System.out.println("在main的栈帧内创建一个arrarray11变量,并在eden区开辟一块1m的内存,变量arr1指向这块你内存");
        byte[] array1 = new byte[size];
        System.out.println("在堆内存的Eden区中创建第二个数组,并且让局部变量指向第二个数组,第一个数组就没人引用了,此时第一个数组就成了没人引用的“垃圾对象”");
        array1 = new byte[size];
        System.out.println("在堆内存的Eden区内创建了第三个数组,同时让array1变量指向了第三个数组,此时前面两个数组都没有人引用了,就都成了垃圾对象");
        array1 = new byte[size];
        System.out.println("array1这个变量什么都不指向了,此时会导致之前创建的3个数组全部变成垃圾对象");
        array1 = null;
        System.out.println("此时会分配一个2MB大小的数组,尝试放入Eden区中,但是Edeb区只剩1m了,所以会触发Minor GC");
        byte[] arr2 = new byte[2 * size];

    }
}

代码分析

  1. byte[] arr1 = new byte[size];这行代码一旦运行,就会在JVM的Eden区内放入一个1MB的对象,同时在main线程的虚拟机栈中会压入一个main()方法的栈帧,在main()方法的栈帧内部,会有一个“array1”变量,这个变量是指向堆内存Eden区的那个1MB的数组,如下图。

在这里插入图片描述

  1. array1 = new byte[size];此时会在堆内存的Eden区中创建第二个数组,并且让局部变量指向第二个数组,然后第一个数组就没人引用了,此时第一个数组就成了没人引用的“垃圾对象”了,如下图所示。
    在这里插入图片描述

  2. array1 = new byte[size];这行代码在堆内存的Eden区内创建了第三个数组,同时让array1变量指向了第三个数组,此时前面两个数组都没有人引用了,就都成了垃圾对象,如下图所示。
    在这里插入图片描述

  3. array1 = null;这行代码一执行,就让array1这个变量什么都不指向了,此时会导致之前创建的3个数组全部变成垃圾对象,如下图。
    在这里插入图片描述

  4. byte[] arr2 = new byte[2 * size];此时会分配一个2MB大小的数组,尝试放入Eden区中,因为Eden区总共就4MB大小,而且里面已经放入了3个1MB的数组了,所以剩余空间只有1MB了,此时你放一个2MB的数组是放不下的,所以这个时候就会触发年轻代的Young GC。

猜你喜欢

转载自blog.csdn.net/u010859650/article/details/127975782
今日推荐