都是以尽可能少而快速地执行GC为设计原则
#### G1是什么 Garbage-First 收集器,是一款面向服务端应用的收集器,应用在多处理器和大容量内存环境中,在实现高吞吐量的同时,尽可能满足垃圾收集暂停时间的要求。另外,它还具有一下特征:
像CMS收集器一样,能与应用程序并发执行
整理空闲空间更快
需要更多的时间来预测GC停顿时间
不希望牺牲大量的吞吐量性能
不需要更大的Java Heap
G1收集器设计目标是取代CMS收集器,它同CMS相比,在以下方面表现的更出色
G1是一个有整理内存过程的垃圾收集器,不会产生很多内存碎片。
G1的Stop The World(STW)更可控,G1在停顿时间上添加了预测机制,用户可以指定期望停顿时间。
CMS垃圾收集器虽然减少了暂停应用程序的运行时间,但是它还存在着内存碎片问题。于是,为了去除内存碎片问题,同时又保留CMS垃圾收集器低暂停时间的优点,JAVA7发布了一个新的垃圾收集器-G1垃圾收集器
G1是在2012版本才在JDK1.7中可用,Oracle官方在JDK9中将G1变成默认的垃圾收集器以替代CMS,它是一款面向服务端应用的收集器,主要应用在多CPU和大内存服务器环境下,极大减少垃圾收集的停顿时间,全面提升服务器的性能,逐步替换Java8以前的CMS收集器
主要改变时:Eden,Survivor和Tenured等内存区域不再是连续了,而是变成一个个大小一样的region,每个region从1M到32M不等。一个region有可能属于Eden,Survivor或者Tenured内存区域。
G1能充分利用多CPU,多核环境硬件优势,尽量缩短STW
G1整体上采用标记-整理算法,局部是通过复制算法,不会产生内存碎片
宏观上看G1之中不再区分年轻代和老年代。把内存划分成多个独立的子区域(Region),可以近似理解为一个围棋的棋盘
G1收集器里面将整个内存区域都混合在一起了,但其本身依然在小范围内要进行年轻代和老年代的区分,保留了新生代和老年代,但他们不再是物理隔离的,而是通过一部分Region的集合且不需要Region是连续的,也就是说依然会采取不同的GC方式来处理不同的区域
G1虽然也是分代收集器,但整个内存分区不存在物理上的年轻代和老年代的区别,也不需要完全独立的Survivor(to space)堆做复制准备,G1只有逻辑上的分代概念,或者说每个分区都可能随G1的运行在不同代之间前后切换。
#### 底层原理 Region区域化垃圾收集器,化整为零,打破了原来新生区和老年区的壁垒,避免了全内存扫描,只需要按照区域来进行扫描即可。
区域化内存划片Region,整体遍为了一些列不连续的内存区域,避免了全内存区的GC操作。
核心思想是将整个堆内存区域分成大小相同的子区域(Region),在JVM启动时会自动设置子区域大小
在堆的使用上,G1并不要求对象的存储一定是物理上连续的,只要逻辑上连续即可,每个分区也不会固定地为某个代服务,可以按需在年轻代和老年代之间切换。启动时可以通过参数`-XX:G1HeapRegionSize=n` 可指定分区大小(1MB~32MB,且必须是2的幂),默认将整堆划分为2048个分区。
大小范围在1MB~32MB,最多能设置2048个区域,也即能够支持的最大内存为:32MB*2048 = 64G内存
Region区域化垃圾收集器
Region区域化垃圾收集器
G1将新生代、老年代的物理空间划分取消了,同时对内存区域进行了划分
G1算法将堆划分为若干个区域(Reign),它仍然属于分代收集器,这些Region的一部分包含新生代,新生代的垃圾收集依然采用暂停所有应用线程的方式,将存活对象拷贝到老年代或者Survivor空间。
这些Region的一部分包含老年代,G1收集器通过将对象从一个区域复制到另外一个区域,完成了清理工作。这就意味着,在正常的处理过程中,G1完成了堆的压缩(至少是部分堆的压缩),这样也就不会有CMS内存碎片的问题存在了。
在G1中,还有一种特殊的区域,叫做Humongous(巨大的)区域,如果一个对象占用了空间超过了分区容量50%以上,G1收集器就认为这是一个巨型对象,这些巨型对象默认直接分配在老年代,但是如果他是一个短期存在的巨型对象,就会对垃圾收集器造成负面影响,为了解决这个问题,G1划分了一个Humongous区,它用来专门存放巨型对象。如果一个H区装不下一个巨型对象,那么G1会寻找连续的H区来存储,为了能找到连续的H区,有时候不得不启动Full GC。 回收步骤
针对Eden区进行收集,Eden区耗尽后会被触发,主要是小区域收集 + 形成连续的内存块,避免内碎片
Eden区的数据移动到Survivor区,加入出现Survivor区空间不够,Eden区数据会晋升到Old区
Survivor区的数据移动到新的Survivor区,部分数据晋升到Old区
最后Eden区收拾干净了,GC结束,用户的应用程序继续执行