G1收集器原理及是否区域划分?如何做到垃圾回收间停顿可控?

上节讲解了:CMS收集器相关知识点

本节讲解:G1收集器相关知识点

G1 收集器

G1垃圾回收器是可以同时回收新生代老年代对象的,不需要两个垃圾回收器配合起来运作,可以搞定所有的垃圾回收。他最大的一个特点就是把Java堆内存拆分为多个大小相等的区域(Region)。

如上,G1有新生代和老年代的概念,但是只不过是逻辑上的概念。而且G1最大的一个特点,就是可以让我们设置一个垃圾回收的预期停顿时间。

G1新生代和老年代就是如上图来化分的么?

在G1中,每一个Region时可能属于新生代,但是也可能属于老年代的,刚开始Region可能谁都不属于,然后接着就分配给了新生代,然后放了很多属于新生代的对象,接着就触发了垃圾回收这个Region,如下图:

然后下一次同一个Region可能又被分配了老年代了,用来放老年代的长生存周期的对象,如图所示:

所以其实在G1对应的内存模型中,Region随时会属于新生代也会属于老年代,所以没有所谓新生代给多少内存,老年代给多少内存这一说了。

G1是如何做到对垃圾回收导致的系统停顿可控的?

其实G1如果要做到这一点,他就必须要追踪每个Region里的回收价值。G1 收集器在后台维护了一个优先列表,每次根据允许的收集时间,优先选择回收价值最大 Region。这种使用 Region 划分内存空间以及有优先级的区域回收方式,保证了G1收集器在有限时间内可以尽可能高的收集效率。

G1很适合大内存机器他必须搞清楚每个Region里的对象有多少是垃圾,如果对这个Region进行垃圾回收,需要耗费多长时间,可以回收掉多少垃圾。如图:

然后在垃圾回收的时候,G1会发现在最近一个时间段内,比如1小时内,垃圾回收已经导致了几百毫秒的系统停顿了,现在又要执行一次垃圾回收,那么必须是回收上图中那个只需要200ms就能回收掉50MB垃圾的Region。于是G1触发一次垃圾回收,虽然可能导致系统停顿了200ms,但是一下子回收了更多的垃圾,就是50MB的垃圾。如图:

所以简单来说,G1可以做到让你来设定垃圾回收对系统的影响,他自己通过把内存拆分为大量小Region,以及追踪每个Region中可以回收的对象大小和预估时间,最后在垃圾回收的时候,尽量把垃圾回收对系统造成的影响控制在你指定的时间范围内,同时在有限的时间内尽量回收尽可能多的垃圾对象。这就是G1的核心设计思路。

那有多少个Region?每个Region的大小是多大呢?

因为JVM最多可以有2048个Region,然后Region的大小必须是2的倍数,比如说1MB、2MB、4MB之类的。比如说堆大小是4G,那么就是4096MB,此时除以2048个Region,每个Region的大小就是2MB。大概就是这样子来决定Region的数量和大小的,大家一般保持默认的计算方式就可以。通过手动方式来指定,参数“-XX:G1HeapRegionSize”。

刚开始的时候,默认新生代对堆内存的占比是5%,也就是占据200MB左右的内存,对应大概是100个Region,这个是可以通过“-XX:G1NewSizePercent”来设置新生代初始占比的,其实维持这个默认值即可。因为在系统运行中,JVM其实会不停的给新生代增加更多的Region,但是最多新生代的占比不会超过60%,可以通过参数来调整“-XX:G1MaxNewSizePercent”。Region进行回收后,新生代的Region还会减少,这个是动态的。

本节结束,下节讲解:G1的新生代垃圾回收及新生代是否还有Eden和Survivor的概念。

声明:本站部分文章内容及图片转载于互联 、内容不代表本站观点,如有内容涉及侵权,请您立即联系本站处理,非常感谢!

(0)
上一篇 2022年4月20日
下一篇 2022年4月21日

相关推荐