G1(Garbage First)收集器是基于标记-整理算法,它避免了内存碎片的问题。
可以非常精确控制停顿时间,既能让使用者明确指定一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不多超过N毫秒,这几乎已经是实时Java(rtsj)的垃圾收集器的特征了。
G1采用了开创性的局部收集的设计思路和以Region为基本单位的内存布局方式,它将Java堆空间划分成多个大小相等的独立区域(Region),JVM目标是总共不超过2048个Region(由JVM源码参数TARGET_REGION_NUMBER定义)。
通常Region的大小等于堆空间总大小除以Region的个数,比如堆空间大小4096MB,总共有2048个Region,那么每个Region的大小为2MB,也可以通过参数-XX:G1HeapRegionSize来指定Region的大小,假设参数值为4MB,那么堆空间就只有1024个Region了,一般推荐默认的计算方式。
G1虽然抛弃了将新生代和老年代作为整块内存空间的方式,但依然保留了新生代和老年代的概念。只是老年代和新生代的内存空间不再是物理连续的,它们都是Region的集合。
G1将所有Region分为四种类型:Eden、Survivor、Old、Humongous。
默认新生代的Region内存占堆空间的5%,如果堆空间大小为4096MB,那么新生代占用200MB左右的内存,按照每个Region为2MB,对应的就是100个Region,也可以通过参数-XX:G1NewSizePercent设置新生代初始占比。
在系统运行过程中,JVM会动态地给年轻代增加更多的Region,但新生代的占比最多不会超过60%,可以通过参数-XX:G1MaxNewSizePercent设置。Region的区域类型是动态变化的,可能之前是新生代,经过了垃圾回收之后就变成了老年代。
G1中的新生代依然与经典垃圾收集器一样,分为Eden区和Survivor区,默认比例也是8:1,如果新生代有100个Region,那么就是Eden区占用80个,两个Survivor区各占用10个。
G1收集器对于对象从新生代转移到老年代与CMS等经典垃圾收集器是一样的,但对于大对象的处理有所不同。G1为大对象的内存分配专门设计了一个Humongous类型的Region,而不再试让对象直接进入老年代的Region。
在进行Full GC的时候除了要收集新生代和老年代的Region外,还会将Gumongous的Region一并进行回收。
G1可以由用户自己去设置STW的最大时间,然后G1会根据STW的时间来进行内存回收,这个STW的时间包含了并发标记、最终标记和筛选回收三个阶段STW的总时间。