JVM管理的内存中,虚拟机栈、本地方法栈和程序计数器的生命周期和线程的生命周期一致,随着栈帧的出栈实现自动的内存清理,因此JVM中需要GC的内存区域主要在Java堆和方法区。
程序所使用的对象和数组填充满Java堆之后,会抛出out of memory异常,程序挂掉,GC机制将不再使用的对象和数组删除,整理内存以便后续使用。
GC如何判断对象是否需要被回收
需要进行回收的对象的已经不再存活的对象(不再使用),判断对象是否存活的方法有:
(1)引用计数(缺点:可能存在循环引用的问题,导致GC无法回收,内存泄漏);
(2)对GC Roots对象可达(Java GC使用的方法);
GC Roots对象有
(1)方法区内 类静态属性/常量 引用的对象;
(2)堆内存中引用的对象;
(3)虚拟栈中引用的堆上的对象;
(4)本地方法栈中引用的堆上的对象;
对象回收的方法
(1)标记清理 ,标记存活的对象,将未标记的对象删除,缺点:造成内存碎片,导致内存足够但是大的内存分配失败;
(2)标记整理,删除垃圾后,将存活的对象前移整理,缺点:代价大;
(3)复制算法,将内存一分为二,GC将存活的对象复制到另一半内存中,然后前该半内存中的垃圾删除,缺点:可用空间只有原来的一半;
(4)分代收集算法,现在的JVM大多是采用这种方式,根据对象的生存周期。将堆分为新生代和老年代,新生代有分为一个Edan区和两个Survivor 区(E区和S区内存大小一般8:1),因此GC又分为Young GC和Old GC。 在新生代中,由于对象周期短(存活对象少),因此Young GC采用复制算法,老年代里对象存活率高,因此Old GC使用标记清理或标记整理算法.
如何触发GC
(1)通过System.gc();手动触发;
(2)JVM自己管理,当内存不足时,自动触发;
1)当新生代的E区满时,触发Young GC,采用复制算法将存活对象复制到S区,并将失活的对象回收;
2)当老年代空间不足 / 方法区空间不足
GC收集器
古早期的GC:
重点讲一下CMS收集器,极大的降低StopTheWorld时间,是服务端常用的垃圾收集器,配合PawNew使用。但是由于采用的是标记清理的算法,存在内存碎片。CMS收集器工作过程:
多次标记:
1 初次标记,标出O区的GCROOT对象和被Y区引用的对象,耗时短,工作时暂停其他线程
2 并发标记,GCRootTracing,时间长,和其他线程一起工作
3 重新标记,修正并发标记中的错误,工作时暂停其他线程
并发清理:
采用标记清除算法,定点清理内存,而不影响其他位置内存,所以可以并发进行,和其他线程一起工作
下面这张图将这种 串行GC,并行GC 以及CMS的多次标记并发清理表达的很清楚。
注:图片截取自https://www.bilibili.com/video/av89885794?p=2
现代的GC:
G1 收集器:JDK9之后主流的GC收集器
G1的内存结构
G1首先在内存结构上采用了region化的方法,将堆内存划分成2000块左右的小块,每块大小1-32M(2的幂次),每块region都可以作为E、S、O以及H区(本质还是O区,存储较大对象)
关于Region的一个关键:Remember Set(Rset), 记录region的对象被其他region对象的引用,目的时缩小标记时所需遍历范围。
YGC采用 标记-复制算法
OGC采用MixGC,优先回收存活对象最少的区,主要工作过程:
多次标记:
(1)初次标记:标记 GCRoots 直接引的对象和所在Region,但是与CMS不同的是,G1不止标记O区。初次标记一般和YGC同时发生。
(2)RootRegion扫描 : 标记 GCRoots所在的region到O区的引用的对象,这个过程会将S区的存活对象存到O区;
(3)并发标记:不需要STW, 并发标记整个堆,这个时候会计算每个区的存活率,如果发现某个Region中所有对象失活,将其标记为X区;
(4)重新标记:短暂STW,收集 并发标记阶段 工作线程产生新的垃圾,并直接删除并发标记过程中标记的X区;G1中采用了比CMS更快的初始快照算法:snapshot-at-the-beginning (SATB);
并发清理:
采用复制-清理算法,并发清除失活对象,会有STW。G1将回收区域的存活对象拷贝到新区域 并 清除Remember Sets,并发清空回收区域并把它返回到空闲区域链表中。
总结G1 收集器和其他收集器(主要是CWS)区别:
1. 内存结构不同。G1 内存结构将JVM管理的内存分成很多的小块,更灵活应用内存;
2. 增加Root Region Scanning阶段,借助Remember Set这一数据结构记录Region中对象在别的Region的引用,缩小标记遍历范围;
3. 重新标记过程中采用比CMS更快的SATB算法,且直接删除X区,提高效率;
4. MixGC优先回收对象存活率低的区,而不是全部清除,达到垃圾清理的要求且最大限度的降低STW时间,提高效率;
5. YGC和OGC均使用的是复制-清理的算法,不会造成垃圾碎片;