各种垃圾收集器,和各种垃圾回收算法,是不是忘了又看,看了又忘?
来零距离观察一下我们日常所用的垃圾收集器,加深了印象才掌握得牢嘛!
一. JDK版本与默认垃圾收集器
首先,我们最常用的是哪个垃圾收集器呢?
要知道,都已经出了jdk16了!不过,虽然已经jdk16了,但是长支持版本可没有几个。来看下官方说法:
https://www.oracle.com/java/technologies/java-se-support-roadmap.html
是的,jdk8和jdk11是官方的长期支持版本,这两个版本默认的垃圾收集器分别是:
jdk8:UseParallelGC
jdk11:ZGC
而业界生产环境广泛使用的版本依然是jdk8,那么就来看看jdk8默认的UseParallelGC吧。
二. JDK8 VM 默认参数
- HotSpot Java虚拟机,用-XX:+PrintCommandLineFlags查看参数,发现Java8默认使用的垃圾收集器就是这个-XX:+UseParallelGC (新生代:Paralle Scavenge收集器,老年代:Parallel Old收集器)
//-XX:+PrintCommandLineFlags,这个参数让JVM打印出那些已经被用户或者JVM设置过的详细的XX参数的名称和值
~ $ java -XX:+PrintCommandLineFlags -version
-XX:InitialHeapSize=134217728 -XX:MaxHeapSize=2147483648 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC
java version "1.8.0_201"
Java(TM) SE Runtime Environment (build 1.8.0_201-b09)
Java HotSpot(TM) 64-Bit Server VM (build 25.201-b09, mixed mode)
- 可以用如下命令查看垃圾收集器详情:
~ $ java -XX:+PrintGCDetails -version
java version "1.8.0_201"
Java(TM) SE Runtime Environment (build 1.8.0_201-b09)
Java HotSpot(TM) 64-Bit Server VM (build 25.201-b09, mixed mode)
Heap
PSYoungGen total 38400K, used 1331K [0x0000000795580000, 0x0000000798000000, 0x00000007c0000000)
eden space 33280K, 4% used [0x0000000795580000,0x00000007956cce48,0x0000000797600000)
from space 5120K, 0% used [0x0000000797b00000,0x0000000797b00000,0x0000000798000000)
to space 5120K, 0% used [0x0000000797600000,0x0000000797600000,0x0000000797b00000)
ParOldGen total 87552K, used 0K [0x0000000740000000, 0x0000000745580000, 0x0000000795580000)
object space 87552K, 0% used [0x0000000740000000,0x0000000740000000,0x0000000745580000)
Metaspace used 2241K, capacity 4480K, committed 4480K, reserved 1056768K
class space used 243K, capacity 384K, committed 384K, reserved 1048576K
三. Parallel GC
- Parallel Scavenge
新生代收集器,采用复制算法,并行的多线程收集器。
主要思想就是,将内存分为eden区和survivor区(from区和to区),默认是8:2的比例。
在GC开始的时候,对象只会存在于Eden区和名为“From”的Survivor区,Survivor区“To”是空的。紧接着进行GC,Eden区中所有存活的对象都会被复制到“To”,而在“From”区中,仍存活的对象会根据他们的年龄值来决定去向。年龄达到一定值(年龄阈值,可以通过-XX:MaxTenuringThreshold来设置)的对象会被移动到年老代中,没有达到阈值的对象会被复制到“To”区域。经过这次GC后,Eden区和From区已经被清空。这个时候,“From”和“To”会交换他们的角色,也就是新的“To”就是上次GC前的“From”,新的“From”就是上次GC前的“To”。不管怎样,都会保证名为To的Survivor区域是空的。Minor GC会一直重复这样的过程,直到“To”区被填满,“To”区被填满之后,会将所有对象移动到年老代中。
- Parallel Old
Parallel Scavenge收集器的老年代版本,使用多线程和标记-整理算法。
复制算法也存在他自己的缺点,比如在对象存活率较高时就要执行较多的复制操作,效率将会变低。更关键的是,如果不想浪费50%的空间,就需要额外的空间进行分配担保,以应对被使用的内存中所有对象都100%存活的极端情况。所有在老年代一版不直接选用这种算法。
- 标记出所需要回收的对象
- 所有存活对象向一端移动
- 清理掉端边界以外的内存
四. Demo感受垃圾收集的过程
- 用jinfo查看jvm基本参数
~ $ jinfo -flag SurvivorRatio 40446(进程号)
-XX:SurvivorRatio=8
- 小例子观察对象优先在Eden分配
package com.example.demo.jvm;
public class JVMTest {
private static int _1MB = 1024*1024;
public static void main(String[] args) {
System.out.println("Parameters: -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8");
byte[] allocation1 = new byte[1 * _1MB];
byte[] allocation2 = new byte[1 * _1MB];
/*byte[] allocation3 = new byte[1 * _1MB];
byte[] allocation4 = new byte[1 * _1MB];
byte[] allocation5 = new byte[1 * _1MB];
byte[] allocation6 = new byte[1 * _1MB];
byte[] allocation7 = new byte[1 * _1MB];
allocation1 = null;
allocation2 = null;
allocation3 = null;
allocation4 = null;
allocation5 = null;
allocation6 = null;
byte[] allocation8 = new byte[1 * _1MB];*/
}
}
Parameters: -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8
Heap
PSYoungGen total 9216K, used 3227K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000)
eden space 8192K, 39% used [0x00000007bf600000,0x00000007bf926fb0,0x00000007bfe00000)
from space 1024K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007c0000000)
to space 1024K, 0% used [0x00000007bfe00000,0x00000007bfe00000,0x00000007bff00000)
ParOldGen total 10240K, used 0K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000)
object space 10240K, 0% used [0x00000007bec00000,0x00000007bec00000,0x00000007bf600000)
Metaspace used 2690K, capacity 4486K, committed 4864K, reserved 1056768K
class space used 288K, capacity 386K, committed 512K, reserved 1048576K
网友评论