JVM垃圾回收(二) 垃圾回收算法
- 标记清除算法
标记清除算法的优点在于速度足够快。但是缺点在于,对部分空间进行清除之后,这一整块的存储空间不连续,所以在这很容易造成内存碎片这种情况。
示意图如下:
- 标记整理算法
标记整理算法和前面的标记清除算法的区别在于多了一个步骤,这里会把内存空间进行整理,也就是说,在清除部分内存之后,会将内存往前移动,该算法的优点在于不会导致内存碎片,但是这种算法的速度比较慢。
示意图如下:
- 复制算法
复制算法:有两个内存空间,将第一个内存空间当中需要的内存区间进行复制到另一块的内存空间当中,到最后再将第二快的内存再一次返回给第一个内存空间当中。
复制算法的优点是不会有内存碎片,但缺点是需要占用双倍内存空间
示意图如下:
- 分代垃圾回收
示意图如下:
步骤如下:
- 对象首先分配在伊甸园区域
- 新生代空间不足时,触发 minor gc,伊甸园和 幸存区from 存活的对象使用 copy 复制到 幸存区to 中,存活的对象年龄加 1并且交换 幸存区from 和 幸存区to
- minor gc 会引发 stop the world,暂停其它用户的线程,等垃圾回收结束(防止复制的时候变量的地址改变导致程序混乱),用户线程才恢复运行
- 当对象寿命超过阈值时,会晋升至老年代,最大寿命是15(4bit)
- 当老年代空间不足,会先尝试触发 minor gc,如果之后空间仍不足,那么触发 full gc,STW的时间更长
- 相关VM参数
- GC 分析
使用以下代码段进行测试:给其划分内存空间。
private static final int _512KB = 512 * 1024;
private static final int _1MB = 1024 * 1024;
private static final int _6MB = 6 * 1024 * 1024;
private static final int _7MB = 7 * 1024 * 1024;
private static final int _8MB = 8 * 1024 * 1024;
添加JVM的参数,运行代码查看输出 -Xms20M -Xmx20M -Xmn10M -XX:+UseSerialGC -XX:+PrintGCDetails -verbose:gc -XX:-ScavengeBeforeFullGC
我们使用一个list数组,加入一个内存空间进去。使用代码段:
ArrayList<byte[]> list = new ArrayList<>();
list.add(new byte[_7MB]);
在前面设置了内存大小,在这内存不够,触发了垃圾回收机制,并且还可以看到伊甸园、幸存区 from 和幸存区 to 所占空间比例。
再往里面进行添加,是内存占用增大,再次查看伊甸园和幸存区 from 和幸存区 to 的所占比例,在这里伊甸园的空间基本上就已经占满了,
我们再添加一个512kb 进如这个list集合当中,可以发现这个时候新生代当中的数据对象会直接晋升到老年代当中。
以及当分配内存的时候,发现新生代当中的内存不够,而老年代当中的内存足够的时候,会直接晋升为老年代,以8m数据内存大小为例
当添加内存的时候,在新生代和老年代的内存都不够进行分配的时候就会抛出异常,也就是堆内存溢出。以添加两个8m的数据内存为例
但是当这段代码运行在线程当中,当内存不足的时候会不会影响到主线程直接结束,很显然是不会导致主线程结束,使用以下代码段进行测试
new Thread(() -> {
ArrayList<byte[]> list = new ArrayList<>();
list.add(new byte[_8MB]);
list.add(new byte[_8MB]);
}).start();
System.out.println("sleep....");
Thread.sleep(1000L);
还没有评论,来说两句吧...