文章目录
- 1.标记清除法(标记不能清除的,清除其余的)
- 2.标记整理法
- 3.标记复制法(标记不能清除的)
- 分代回收思想:
- 三色标记法
- 漏标问题
- 垃圾回收规模:
- 什么是STW?
- 并发标记
- 常见的垃圾回收器的实现
- Parallel GC
- ConcurrentMarkSweep GC
- G1 GC
java垃圾回收的区域是虚拟机堆。
1.标记清除法(标记不能清除的,清除其余的)
沿着GC Root对象(一定不会被清除的对象)的引用链往下找,对引用链上的对象都加上标记,清除那些没有被标记的对象。
一个对象不能被清除,那他的引用链上的对象必须也不能清除,不能说我想用的时候拿到的是null,那这样就没法用了。
缺点:清除后得到的内存不连续,内存碎片用处不大。
应用场景:无,目前已经废弃。
2.标记整理法
标记清除法的基础上增加一步整理动作,把不连续的内存变为连续的。
缺点:性能低,因为多了整理动作。
应用场景:堆内存老年代的垃圾回收机制。
因为老年代存活对象多,垃圾对象少,使用标记复制法要复制的对象太多了而且老年代占用内存多,如果使用标记复制法需要准备更多的另一块内存空间。
3.标记复制法(标记不能清除的)
标记不能被清除的对象,然后把这些对象直接移动到另一个区域,这片区域直接作废,另一片区域也不再需要进行整理。
缺点:占用一份额外的内存。
应用场景:用于堆内存的新生代的垃圾回收机制。
因为新生代能存活对象比较少,垃圾对象多。只需要简单复制很少的一部分对象,就能完成工作。而且新生代占用的内存少,所需另一块内存空间也少。
新生代中eden区复制到survicor区的垃圾回收示例:
一个对象首先被分配到Eden区,当Eden区满时,会触发一次Minor GC。把Eden区中存活的对象复制到其中一个Survivor区(),同时清理掉不再被引用的对象。
新生代的from区复制到to区的垃圾回收示例:
- 将整个内存分成两个大小相等的区域,from 和 to,其中 to 总是处于空闲,from 存储新创建的对象
- 标记阶段与前面的算法类似
- 在找出存活对象后,会将它们从 from 复制到 to 区域,复制的过程中自然完成了碎片整理
- 复制完成后,交换 from 和 to 的位置即可
分代回收思想:
我们将虚拟机堆分为新生代和老年代,新生代和老年代特性不同,所以我们用不同的垃圾回收策略。
三色标记法
前面我们说到对引用链上的对象添加标记,三色标记法就是其中一种实现。
即用三种颜色记录对象的标记状态
- 黑色 – 已标记(沿着跟对象的引用链找到这个对象了,并且这个对象中引用的对象也标记完成了)
- 灰色 – 标记中(沿着跟对象的引用链找到这个对象了,但是这个对象中引用的其他对象还在标记中)
- 白色 – 还未标记
1.起始的三个对象还未处理完成,用灰色表示
2.该对象的引用已经处理完成,用黑色表示,黑色对象引用的对象变为灰色
3.依次类推
4. 沿着引用链都标记了一遍
5.最后为标记的白色对象,即为垃圾
漏标问题
先进的垃圾回收器都是支持并发标记的,即标记的线程和用户线程同时工作,这就会带来一个问题,如果在标记的过程中,用户修改了已经被标为黑色的对象 的引用对象,这个新对象就会一直是白色,被标为垃圾对象,最后被垃圾回收掉,导致引用为null无法正常工作。
解决办法:
1.增量更新法(Incremental Update)
思路是拦截每次赋值动作,只要赋值发生,被赋值的对象就会被记录下来不做处理,等标记完成后,把用户线程停止一段时间然后把被记录下来的对象变为灰色再标记一遍。
2.原始快照法(Snapshot At The Beginning)G1(GC的具体实现) 垃圾回收器采用
思路也是拦截每次赋值动作,不过记录的对象不同,然后在重新标记阶段对这些被标记的对象二次处理.
新加对象会被记录
被删除引用关系的对象也被记录
垃圾回收规模:
-
Minor GC 发生在新生代的垃圾回收,暂停时间短
-
Mixed GC 新生代 + 老年代部分区域的垃圾回收,G1 垃圾回收器特有
-
Full GC 新生代 + 老年代完整垃圾回收,暂停时间长,应尽力避免
什么是STW?
STW: Stop-The-World,是在垃圾回收算法执⾏过程当中,需要将JVM内存冻结的⼀种状态。在STW状态下,除了垃圾回收线程外JAVA的所有线程会停止,native⽅法可以执⾏,但是,不能与JVM交互。GC各种算法优化的重点,就是减少STW。
并发标记
在垃圾回收(Garbage Collection)中,并发标记是指在进行垃圾回收时,程序的执行和垃圾回收的标记过程可以同时进行,即并发执行。
常见的垃圾回收器的实现
Parallel GC
Paraller-并行的
Parallel GC(Parallel Collector):也称为吞吐量优先收集器,使用多个垃圾回收线程并行进行垃圾回收,适用于需要高吞吐量的应用程序。
- eden 内存不足发生 Minor GC,需要暂停用户线程STW
- old 内存不足发生 Full GC,需要暂停用户线程STW
- 注重吞吐量
ConcurrentMarkSweep GC
CMS收集器(Concurrent Mark-Sweep Collector):是一种并发垃圾回收器,旨在减少垃圾回收造成的停顿时间。
-
它是工作在 old 老年代,支持并发标记的一款回收器,采用并发标记清除算法(所以已经废弃)
- 并发标记时不需暂停用户线程
- 重新标记时仍需暂停用户线程
-
如果并发失败(即回收速度赶不上创建新对象速度),会触发 Full GC
-
**注重响应时间
G1 GC
JDK9开始作为默认垃圾回收器.G1垃圾回收器兼顾吞吐量与响应时间。
原理:把整个虚拟机堆划分为多个大小相等的区域,每个区域都可以充当eden区,survivor区,old区,humongous区域,其中 humongous 专为大对象准备。
- 分成三个阶段:新生代回收、并发标记与混合收集
- 如果并发失败(即回收速度赶不上创建新对象速度),会触发 Full GC
新生代中的回收
- 初始时,所有区域都处于空闲状态
-
创建了一些对象,挑出一些空闲区域作为伊甸园区存储这些对象
-
当伊甸园需要垃圾回收时,挑出一个空闲区域作为幸存区,用复制算法复制存活对象,需要暂停用户线程
-
复制完成,将之前的伊甸园内存释放
- 创建了一些对象,再次挑出一些空闲区域作为伊甸园区存储这些对象,随着时间流逝,伊甸园的内存又有不足
- 将伊甸园以及之前幸存区中的存活对象,采用复制算法,复制到新的幸存区,其中幸存区中较老对象会晋升至老年代
- 释放伊甸园以及之前幸存区的内存
并发标记与混合收集
-
当老年代占用内存超过阈值(老年代内存占比达到堆内存的45%以上)后,触发并发标记(标记的同时不暂停用户线程)
-
并发标记之后,会有重新标记阶段解决漏标问题,此时需要暂停用户线程。这些都完成后就知道了老年代有哪些存活对象。
随后进入混合收集阶段。此时不会对所有老年代区域进行回收,而是根据预期暂停时间优先释放对象少,能释放更多内存)的区域(这也是 Gabage First 名称的由来)。
- 混合收集阶段中,参与复制的有 eden、survivor、old,下图显示了伊甸园和幸存区的存活对象复制
- 老年代存活对象少的区域复制到新的老年代区域,幸存区中达到晋升条件的幸存对象晋升到新的老年代
- 复制完成,内存得到释放。进入下一轮的新生代回收、并发标记、混合收集