18_G1 分代回收原理
1066字约4分钟
2024-08-10
G1 对应内存大小设置
我们知道了 G1
对应的是一大堆的 Region
内存区域,每个 Region
大小是一致的
那到底有多少个 Region
呢?每个 Region
的大小是多少呢?
我们用 -Xms
和 -Xmx
设置堆内存大小,用 -XX:+UseG1GC
参数指定垃圾回收器,JVM
启动的时候看到使用的是 G1
垃圾回收器,此时会自动用堆大小除以 2048
因为 JVM
最多可以有 2048
个 Region
,每个 Region
的大小必须是 2
的倍数,比如堆大小是 4G
,4096MB
除以 2048
个 Region
,每个 Region
的大小就是 2MB
,如下图
大概就这样子来决定 Region
的数量和大小的,保持默认的计算方式就可以了,当然,也可以通过 -XX:G1HeapRegionSize
指定 Region
大小
一开始,新生代对堆内存的占比默认是 5%
,也就是占据 200MB
左右的内存,对应 100
个 Region
,可以通过 -XX:G1NewSizePercent
来设置新生代初始占比
在系统运行中,JVM
会不停的给新生代增加更多的 Region
,但占比不会超过 60%
,可以通过 -XX:G1MaxNewSizePercent
一旦 Region
如果进行了垃圾回收,新生代的 Region
数量还会减少,这些都是动态的
新生代还有 Eden 和 Survivor 的概念吗
虽然 G1
中把内存划分为了很多的 Region
,但是还是有新生代、老生代的区分
属于新生代的 Region
中,还是可以区分哪些属于 Eden
,哪些属于 Survivor
新生代的参数 -XX:SurvivorRatio=8
,比如说新生代初始的时候有 100
个 Region
,那么 80
个 Region
就是 Eden
,两个 Survivor
各占 10
个 Region
随着对象不停的在新生代里分配,属于新生代的 Region
会不断增加,Eden
和 Survivor
对应的 Region
也会不断增加
G1 新生代垃圾回收
既然 G1
的新生代也有 Eden
和 Survivor
的区分,那么触发垃圾回收机制也都是类似的
随着不停的在新生代 Eden
对应的 Region
中放对象,JVM
就会不停的给新生代加入更多的 Region
,直到新生代占堆大小的最大比例 60%
,假设 1000
个 Region
,Eden
可能占 800
个 Region
,每个 Survivor
100
个 Region
Eden
区占满了对象时触发新生代的 GC
,G1
就会用之前说过的复制算法来进行垃圾回收,进入 Stop the World
状态
将 Eden
对应 Region
中的存活对象放入 S1
的 Region
中,接着回收掉 Eden
对应的 Region
中的垃圾对象
这个过程和之前有区别,G1
可以设置目标 GC
最多可以让系统停顿多长时间,通过 -XX:MaxGCPauseMils
参数设置,默认值是 200ms
对象什么时候进入老年代
按照默认新生代最多只能占据堆内存 60%
的 Region
来推算,老年代最多可以占 40%
的 Region
对象进入老年代的条件和之前几乎是一样的:
1、对象在新生代躲过了很多次垃圾回收,达到了一定年龄进入老年代,参数
-XX:MaxTenuringThreshold
参数设置2、动态年龄判定规则,某次新生代
GC
后,存活对象超过了Survivor
的50%
大对象 Region
以前说的大对象可以直接进入老年代,那 G1
这套内存模型下呢?
G1
提供了专门的 Region
来存放大对象,而不是让大对象进入老年代的 Region
中
在 G1
中,大对象的判定规则是一个大对象超过了一个 Region
大小的 50%
,就会被放入大对象专门的 Region
中
如果一个对象太大,可能会横跨多个 Region
来存放
在 G1
中,新生代和老年代的 Region
是不断变化的,很多空着的 Region
可以用来存放大对象
在新生代、老年代垃圾回收的时候,会顺带着大对象 Region
一起回收