垃圾回收就是对程序中不再使用的内存资源进行自动回收的操作。
1.1 常见的垃圾回收算法:

  • 引用计数:每个对象维护一个引用计数,当被引用对象被创建或被赋值给其他对象时引用计数自动加 +1;如果这个对象被销毁,则计数 -1 ,当计数为 0 时,回收该对象。
    • 优点:对象可以很快被回收,不会出现内存耗尽或到达阀值才回收。
    • 缺点:不能很好的处理循环引用
  • 标记-清除:从根变量开始遍历所有引用的对象,引用的对象标记“被引用”,没有被标记的则进行回收。
    • 优点:解决了引用计数的缺点。
    • 缺点:需要 STW(stop the world),暂时停止程序运行。
  • 分代收集:按照对象生命周期长短划分不同的代空间,生命周期长的放入老年代,短的放入新生代,不同代有不同的回收算法和回收频率。
    • 优点:回收性能好
    • 缺点:算法复杂
      1.2 三色标记法 (从白天到黑夜)
  • 初始状态下所有对象都是白色的。
  • 从根节点开始遍历所有对象,把遍历到的对象变成灰色对象
  • 遍历灰色对象,将灰色对象引用的对象也变成灰色对象,然后将遍历过的灰色对象变成黑色对象。
  • 循环步骤3,直到灰色对象全部变黑色。
  • 通过写屏障(write-barrier)检测对象有变化,重复以上操作
  • 收集所有白色对象(垃圾)。
    1.3 STW(Stop The World)
  • 为了避免在 GC 的过程中,对象之间的引用关系发生新的变更,使得GC的结果发生错误(如GC过程中新增了一个引用,但是由于未扫描到该引用导致将被引用的对象清除了),停止所有正在运行的协程。
  • STW对性能有一些影响,Golang目前已经可以做到1ms以下的STW。
    1.4 写屏障(Write Barrier)
    写屏障是为了提升STW的性能,缩短STW的时间。
    .
    当引用关系发生变化, 新增对象,都将这些对象标记为灰色.
  • 为了避免GC的过程中新修改的引用关系到GC的结果发生错误,我们需要进行STW。但是STW会影响程序的性能,所以我们要通过写屏障技术尽可能地缩短STW的时间。
    造成引用对象丢失的条件:···············
    一个黑色的节点A新增了指向白色节点C的引用,并且白色节点C没有除了A之外的其他灰色节点的引用,或者存在但是在GC过程中被删除了。以上两个条件需要同时满足:满足条件1时说明节点A已扫描完毕,A指向C的引用无法再被扫描到;满足条件2时说明白色节点C无其他灰色节点的引用了,即扫描结束后会被忽略 。
    写屏障破坏两个条件其一即可
  • 破坏条件1:Dijistra写屏障
    满足强三色不变性:黑色节点不允许引用白色节点 当黑色节点新增了白色节点的引用时,将对应的白色节点改为灰色
  • 破坏条件2:Yuasa写屏障
    满足弱三色不变性:黑色节点允许引用白色节点,但是该白色节点有其他灰色节点间接的引用(确保不会被遗漏) 当白色节点被删除了一个引用时,悲观地认为它一定会被一个黑色节点新增引用,所以将它置为灰色

https://www.cnblogs.com/Delo/articles/12553593.html

发表回复