### 标记清除法
在标记阶段会为所有活动对象打上标记,首先标记通过根直接引用的对象,然后递归的别偶记通过指针数组可以访问的对象,有些函数可能会多次调用,为避免重复标记,每次标记前会检查是否已标记,若已标记,则不处理
清除阶段:遍历堆,如果是标记了的对象,则取消标记准备下次GC,若未标记,则回收(连接到空闲链表),之后需要空间,遍历这个空闲链表即可
分配:遍历空闲链表,寻找合适大小的块(也就是内存空间)的操作
如果找到刚好合适的块,直接返回,如果找到比所需更大的块,会切割这个大的分块,没有找到则返回NULL,本次分配失败(First-Bit)
其实分配策略有3种,上边的叫First-Bit
Best-Bit:遍历空闲链表,返回>=size的最小分块
Worst-Bit:找到空闲链表中最大的分块,将其分割成size和剩余,目的是剩余后的分块最大化,这样容易出现大量的小的分块,不推荐
合并:分配过程中会产生大量小的分块,把这些分块连接起来的过程
优点:实现简单,且与保守式GC兼容
缺点:碎片化,分配速度,与写时复制不兼容
最糟糕的是每次都遍历到空闲链表的最后才找到合适的块
写时复制:在Linux中fork()子进程时,并未复制内存空间,而是共享了内存空间,等待子进程有数据写入时,才会真正的创建自己的空间
实现方式:单个空闲链表-->多个空闲链表(指定个数)
BiBop:Big Bag of Page也就是将相近大小的块整理成固定大小的块
把堆整理成固定大小的块(比如分割成2个字和3个字的块),每个块只能分配通用大小的对象就是BiBop的做法,但这样在多个块中分散着同样大小的对象,反而会降低堆使用效率
位图标记:只记录各个对象的标志位并表格化
index = (obj_num+offset)/length
offset = (obj_num+offset)%length
位图标识的优点:1)不对对象设置标识,减少无谓复制,但在Linux C环境和频繁fork()的情况下,位图标记是会被复制的
2)清除阶段更高效,把各个对象的标志位集中到一起即可
注意,在堆为多个的情况下通常会为每个堆都准备一个位图表格
延迟清除法:在分配时直接调用lazy_sweep()函数,若能清除操作来分配分块,就返回分块,若不能则执行标记操作,它会一直遍历堆,直到找到大于或等于所申请的分块为止,它只在分配时执行必要的遍历,不会一下子遍历整个堆
### 增量式垃圾回收( 三种算法 )
三色标记法:将GC中的对象安装各自的情况分为三种,白色(还未搜索过) 灰色(正在搜索) 黑色(搜索完成)
GC运行前所有的对象都是白色,灰色对象依次从栈中取出,其子对象也会被涂成灰色,当所有的子对象变成灰色时,该对象就会被涂成黑色,当GC运行结束,所有的活动对象全部变成黑色,垃圾则为白色
a,根查找阶段 b 标记阶段 c 清除阶段
根查找阶段只在GC运行时执行一次,标记会分段进行,操作一定次数后就暂停标记,执行mutator
清除阶段同标记阶段是增量进行的(incremental_gc())
标记阶段又会出现标记遗漏的情况,可以用写入屏障来解决,就是在引用白色对象的时候,同时将其涂成灰色对象
分配:如果分块的总量小于一定的值,就执行GC
停止型GC是在分块完全枯竭的情况下才进行的
pickup_trunc()用于搜索空闲链表
增量式回收适合那些相对更重视缩短最大暂停时间而不是最大吞吐量的应用程序
最大吞吐量和最大暂停时间是难以调和的,要根据应用程序的类型来权衡取舍