G1
解决的问题G1
垃圾回收器是04
年正式提出,12
开始正式支持,在17
年做为JDK9
默认的垃圾处理器。
java
在04
年的时候,java
程序堆的内存愈来愈大,从而致使程序中可存活的活对象愈来愈多,所以GC
的STW
时间愈来愈长。这是G1
要解决的主要问题:STW
带来的停顿时间太长了。算法
CMS
在此以前效率也很高,但活对象数量一多,STW
时间也很长。并且CMS
没法解决内存碎片化的问题。shell
G1
还解决的问题是:CMS
在GC
后,没法compact
内存。多线程
G1
达成的目标(1)减小因为STW
而带来的程序延迟时间,作到伪实时、低延时、可设定目标;
可设定目标是指可以设置GC
最大STW
停顿的时间,G1
会尽可能达成目的,但不必定达成。并发
-XX:MaxGCPauseMillis=N
默认状况下是250毫秒oracle
(2)解决CMS
在GC
后,没法压缩程序内存的问题;app
(3)在JDK9
以后,默认的垃圾处理器就是G1
;它适用于堆内存较大的状况下(>4~6G
);布局
G1
垃圾回收器G1
内存布局G1
再也不遵循以前的堆中对象的分代排列,而是将堆分红若干个等大的区域。
线程
而是变成:
3d
默认是分红
2048
个区域,-XX:G1HeapRegionSize=N 2048
Humongous
:当你分配的一个对象超过一半区域的大小时,这个对象就会被放入这个区域。这个区域属于老年代区域。
G1
的介绍G1
垃圾回收器再也不回收整个堆,而是选择一个Collection Set
(CS
)。并且每次GC
时,会估计每一个Region
中的垃圾比例,优先回收垃圾多的Region
。这就为何被叫作Garbage First
算法。这也是为何G1
能够控制STW
停顿时间的缘由。
G1
含有三种GC
算法:
Full young GC
:年轻代GC
算法:STW
、Parallel
、Copying
GC
算法:Mostly-concurrent marking
、Incremental compaction
Mixed GC
:混合GC
G1
引来的问题G1
将年轻代、老年代区域划分为许多个小区域,增长在GC
判断对象是否为垃圾的难度。好比:
Region
间的互相引用假设在Full young GC
时,某个年轻代Region
对象可能被老年代的某个对象引用,那么我在回收这个年轻代Region
时,怎么知道这里面的对象是否被其余Region
、老年代引用呢?
Remembered Set
、Card Table
一、CardTable
每一个Region
中分为不少区域,每一个区域咱们成为CardTable
,对应的就是上述蓝色区域;每一个CardTable
有多个entry
组成。当对应的内存空间发生改变时,就会标记为dirty
。
二、RememberedSet
当Region1
的CardTable
引用Region2
的CardTable
时,Region2
的RememberedSet
就会记录对应CardTable
中的entry
,能够根据其找到对应的内存区域。
三、解析
当某个内存对应进行赋值是,就是对象的set
方法,咱们能够在这种方法上添加dirty
的描述。
这其实就是典型的时间换空间的作法:用额外的空间维护引用信息,这就是占用5~10%
的过多内存占用。
一、Write Barrier
介绍
Write barrier
是一种向JVM
注入的一小段代码,用于记录指针变化。好比说object.field = <reference>
。
在JVM
开始更新指针时,就通过如下几步:
Card
为Dirty
Card
存入Dirty Card Queue
队列中这里有一个问题:为何要放在队列里,而不是直接去更新RememberedSet
呢?
这是由于JVM
运行可能会有多个线程并行的修改RememberedSet
,这样就须要花费额外的时间来解决多线程同步问题。而这种更新引用是频繁的,因此这种额外时间是没法忍受的。
二、Dirty Card Queue
这个队列有白、绿、黄、红四个颜色,表示应用线程往这个队列听任务的状态。
White
表示没有应用线程往队列里听任务,什么事都不用干。
Green
此时Refinement
线程开始被激活,开始更新RS
。-XX:G1ConcRefinementGreenZone=N
Yellow
此时所有的Refinement
线程都被激活,来更新RS
。-XX:G1ConcRefinementYellowZone=N
Red
这个时候,应用线程也开始参与排空队列的工做。-XX:G1ConcRefinementRedZone=N
GC
算法的过程Fully young GC
GC
的过程(1)STW
此时会暂停全部堆中的对象,将部分Region
拷贝到指定区域。
(2)构建Collection Set
fully young GC
就是选取全部的Eden
和Survivor
。
(3)扫描GC Roots
(4)更新RememberedSet
排空Dirty Card Queue
(5)Process RS
根据RS
找到要GC
的对象被哪些对象引用了。
(6)对象拷贝
survivor
区域对象的调整。
(7)Reference Processing
G1
记录每一个阶段的时间,用于后期自动调优。好比说会记录Eden
、Survivor
的数量和GC
时间,后期会根据咱们以前设定的暂停目标来自动调整Region
数量。
可是咱们设置暂停目标越短,年轻代的Region
数量就越少。但这可能会致使Fully young GC
频繁发生。
Old GC
当堆用量达到必定程度时,就会触发old GC
。能够经过如下参数进行设置:
-XX:InitatingHeapOccpancyPercent=45
old GC
有一个很大特色就是并发进行的。但它是如何在堆中不断变化的状况下,肯定哪些是要清理的垃圾对象呢?
这种算法实现了在不暂停应用线程的状况下进行并发标记,标记过程过以下:
(1)将GC Root
对象记录为黑色,其直接引用对象记录为灰色,并将这些灰色对象放入一个队列中
(2)从队列取出对象,将其标为黑色,将其引用对象记录为灰色,再放入队列中
(3)直到队列中无对象为止
Lost Object Problem
三色标记算法并无彻底将全部的活对象都标记出来,这就是Lost Object Problem
问题。好比说:
(1)刚开始时
(2)在即将描述将C
标为灰色的一刹那
此时,C
依然是活对象,可是已经没法将其标记了。
(3)结果
Lost Object Problem
的解决这种解决办法仍是经过Write barrier
技术来解决。当B.c=null
,也就是C
指针被删除时,G1
仍是被认为活对象。
那若是
C
是新生对象呢?这是老年代GC
Old GC
过程(1)STW
老年代GC
会在这个时候,进行一次Fully young GC
(2)恢复应用线程
(3)使用三色标记算法并发标记(init marking
)
(4)STW
这时候会有一个Remark
阶段,主要是解决SATB
、Reference processing
还会有一个Cleanup
阶段,用于回收全为空的区
(5)恢复应用线程
Mixed GC
咱们直到CMS
最大的缺点就是没法进行压缩操做,而G1
就经过Mixed GC
解决了这个问题。
Mixed GC
没有固定触发条件,他是根据Fully young GC
收集的信息和咱们配置的时间来决定,是否触发Mixed GC
。它会根据暂停目标,来优先选择垃圾最多的Old Region
来执行。
Mixed GC
会选择若干个Region
进行,默认是选择1/8
的Old Region
、Eden Region
、Survivor Region
。
Mixed GC
的过程跟Fully young GC
的过程相同,都是:STW
、Parallel
、Copying
。