1 标记-清除算法
标记-清除算法是最基础的算法,算法分为标记和清除两个阶段,首先标记出要清除的对象,在标记完后统一回收所有被标记的对象,标记方式为j《jvm系列之垃圾收集器》里面所提到的。这种算法标记和清除两个过程效率都不高;并且在标记清除后,内存空间变得很零散,产生大量内存碎片。当需要分配一个比较大的对象时有可能会导致找不到足够大的内存。
标记清除算法图解(图片来源于百度图片):
3 清除-复制算法
为了解决标记清除效率低的问题,出现了复制算法;这种算法将内存划分为大小相等的两块内存,只使用其中一块。当这一块内存使用完了就将存活的对象复制到另一块上面去,然后把已使用的内存空间一次性清理掉,这种方法不必考虑内存碎片的情况,运行高效,实现简单。缺点是浪费了一半的内存。复制算法图解(图片来源百度图片):
3 标记-整理算法
复制收集算法在对象存活率较高的时候就要进行较多的复制操作,导致效率变低。而且老年代很少会有内存回收,对老年代而言,复制算法做了大量的无用功。针对复制算法存在的的问题,有人提出了标记-整理算法。标记过程和标记-清除算法过程一样,但后续不是直接对可回收对象进行清理,而是让所有存活对象都向一方移动,整理内存,然后再进行清理。标记-整理算法图解(图片来源百度图片):
4 分代收集算法
分代收集算法思路是根据对象存活周期不同将内存划分为几块。一般是分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。在新生代中每次收集时都会回收很多内存,选用高效率的复制算法,并且只需要预留少量的复制空间,用于复制存活对象。老年代中因为对象存活率高,采用标记-整理或标记清理算法节省内存空间提高清理效率。
5 各版本jdk垃圾收集器一览
收集器名称 | 区 域 | 说明 |
---|---|---|
Serial | 新生代 | 单线程,GC时必须停止其它线程直到收集结束;JVM运行在client模式下新生代的默认收集器,简单有效;采用复制算法 |
ParNew | 新生代 | Serial收集的多线程版,保留Serial的参数控制,算法等,暂停所有用户线程,采用复制算法;JVM运行在server的首先的新生代收集器;只有它能和CMS配合工作 |
Parallel Scavenge | 新生代 | 采用复制算法,并行的多线程收集器,与ParNew不同的是,关注点不是停顿时间,而是可控制的吞吐量,即运行用户代码的时间/(运行用户代码的时间+垃圾收集的时间)。可设置最大GC时间和吞吐量大小等参数,也可以让JVM自适应调整策略 |
CMS | 新生代 | concurrent Mark Sweep,已获取最短回收停顿为目标,大部分的互联网站及服务端采用的方式,标记-清除算法 |
G1 | 新生代/老年代 | 收集器最前沿版本,JDK 1.7,代替CMS的新产品 |
Serial Old(MSC) | 老年代 | Serial的老年版,单线程收集器,采用标记-整理算法,主要是client模式的JVM使用 |
Parallel Old | 老年代 | Parallel Scavenge的老年版,多线程,标记整理算法 |
### jdk11 垃圾收集器——ZGC | ||
(网上搜的)ZGC是一个处于实验阶段的,可扩展的低延迟垃圾回收器,旨在实现以下几个目标: | ||
- 停顿时间不超过10ms | ||
- 停顿时间不随heap大小或存活对象大小增大而增大 | ||
- 可以处理从几百兆到几T的内存大小 |
限制:
- 当前版本不支持类卸载
- 当前版本不支持JVMCI
ZGC包含10个阶段,但是主要是两个阶段标记和relocating。GC循环从标记阶段开始,递归标记所有可达对象,标记阶段结束时,ZGC可以知道哪些对象仍然存在哪些是垃圾。ZGC将结果存储在每一页的位图(称为live map)中。在标记阶段,应用线程中的load barrier将未标记的引用压入线程本地的标记缓冲区。一旦缓冲区满,GC线程会拿到缓冲区的所有权,并且递归遍历此缓冲区所有可达对象。注意:应用线程负责压入缓冲区,GC线程负责递归遍历。
标记阶段后,ZGC需要迁移relocate集中的所有对象。relocate集是一组页面集合,包含了根据某些标准(例如那些包含最多垃圾对象的页面)确定的需要迁移的页面。对象由GC线程或者应用线程迁移(通过load barrier)。ZGC为每个relocate集中的页面分配了转发表。转发表是一个哈希映射,它存储一个对象已被迁移到的地址(如果该对象已经被迁移)。GC线程遍历relocate集的活动对象,并迁移尚未迁移的所有对象。有时候会发生应用线程和GC线程同时试图迁移同一个对象,在这种情况下,ZGC使用CAS操作来确定胜利者。一旦GC线程完成了relocate集的处理,迁移阶段就完成了。虽然这时所有对象都已迁移,但是旧地引用址仍然有可能被使用,仍然需要通过转发表重新映射(remapping)。然后通过load barrier或者等到下一个标记循环修复这些引用。