gc种类分为

1.标记-清除算法
通过标记阶段将所有活动对象做上标记,在清理阶段清除没有标记的死亡对象。

gc() { mark_phase() { for(r : roots) mark(r) }; sweep_phase(); }

roots 为用户变量、调用栈、寄存器。

优点:
    实现简单
    gc时不会移动对象
缺点:
    内存碎片化、
    分配速度慢(与其他的GC算法<复制、标记-压缩>可分配内存是连续的不同,该算法空闲内存为链表,极端情况可能遍历整个链表)、
    与写时复制不兼容(同上一样,内存空间不连续,gc时修改标志位会导致大部分对象需要被复制)
改进:
    多个空闲内存链表(链表按内存块大小区分,节省遍历时间)
    分配大小相近的固定内存分块(比如申请800字节,只给1024字节的空间)
    位图标记(将对象标记与对象分开,这样写时复制时只复制了位图的内存)
    延迟清除(分配内存时执行一定清理工作以节省在stw时整体时间)

2.引用计数算法
通过在分配的内存对象前增加几位用于保存被引用次数。在计数为0时释放内存。使用该算法的程序无需主动调用gc()函数

优点:
    立刻回收垃圾(在update操作中计数为0就立即被加入空闲链表)
    最大暂停时间短(stw时间短)
    不需要遍历
缺点:
    计数器操作频繁压力大
    计数器需要占用很大空间(理论情况下,一个32位程序可能有2^32个指针,都可能指向一个对象,那计数器为保持不出现异常至少需要32位空间,而当对象是char或short时就有些本末倒置了,效率低下)
    实现复杂
    循环引用无法回收
改进:
    延迟引用计数(但是失去了引用计数最大优点:立即回收)
    sticky引用计数法(计数器位空间很小,比如只给5位,如果有对象被引用次数超过可表达上限,可以有下面2种方法处理)
        1.啥都不做。事实很多研究表明,大部分对象一出生就死亡,计数器就在0和1之间变化。
        2.在适当时机使用标记-清理算法作为补充。
    1位标记法(sticky的极端情况,优点是高速缓存命中优化,缺点极端不通用)
    部分标记-清除算法(四种颜色巴拉巴拉不懂,优点解决循环引用,缺点丧失了引用计数stw时间短的最大优点)

3.gc复制算法
利用2个相同大小的内存空间进行分配清除。在from空间分配,当空间已满则将内存复制整理转移到to空间。如此循环。

对象头部会有是否被复制的tag。

优点:
    优秀的吞吐量(和标记-清除算法(搜索活动对象,清理死亡对象)相反,复制算法只复制活动对象,)
    高速分配(空间内存为连续空间,而非链表)
    不会产生碎片(空间内存非链表)
    高速缓存命中优化
缺点:
    内存/堆空间使用率低下(只是用一半)
改进:
    多空间复制(将空间分为多份,其中2份执行复制算法,其他执行标记-清除算法)解决了空间利用率低的问题,但同样引入标记-清除的缺点

4.gc标记-压缩算法
标记和1标记-清除的标记一样,压缩阶段产生的效果和3复制算法一样,但是不用牺牲空间。

优点:
    有效利用空间
缺点:
    压缩阶段耗时

5.分代式gc算法

分代式gc算法把对象根据活动时间长短(年龄)分成几代,使用不同的gc算法。新申请的对象为新生代,到达一定年龄的称为老年代
分代式gc算法不是独立的算法,而是将标记-清除、复制算法合理一并使用的算法。
如,新生代对象一般很快就死去,所以进行选择查找活动对象的gc算法(标记-清除的标记阶段、复制算法),这样时间短。老年代对象很难称为垃圾,则可以减少gc频率。

优点:
    吞吐量改善
缺点:
    ”很多对象年纪轻轻就会死“这个经验并不适用所有情况。
改进:
    多代式gc算法(十八代)

6.增量式gc算法
通过逐渐推进gc来控制最大stw时间的方法。通过三种颜色(白灰黑,白:还未搜索的对象,灰:正在搜索的对象,黑:搜索完成的对象)标记,控制gc的节奏

优点:
    缩短最大暂停时间(增量式垃圾回收不是一口气运行 GC,而是和 mutator 交替运行的)
缺点:
    吞吐量降低

v8 GC算法

v8 gc是准确型gc。所有对象通过Object对象准确引用。通过HandleScope作为根进行管理,

v8 gc属于分代式gc,新生代使用复制算法,老年代使用标记-清除算法和标记压缩算法。