4

GC

 2 years ago
source link: https://helloteemo.github.io/2021/07/13/Golang/%E5%9F%BA%E7%A1%80/GC/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
发表于 2021-07-13 更新于 2021-09-20 分类于 Golang基础 阅读次数: 9 本文字数: 1.2k 阅读时长 ≈ 1 分钟

这里只是简单介绍一下GC,我本人对于GC的了解并不是特别深入

垃圾回收算法

首先我们来介绍一下GC算法的大致思路。

  1. 引用计数:每个对象维护一个域,其中保存其它对象指向它的引用数量,当引用数量为零时该对象为垃圾
  2. 标记-清除:首先使用标记算法标记一些对象为不可达对象,之后在达到某个阈值或者固定时间的话,这个时候系统会挂起用户程序,也就是SWT,转而执行垃圾回收算法
  3. 分代收集:分代垃圾回收算法将对象按生命周期长短存放到堆上的两个(或者更多)区域,这些区域就是分代(generation)。之后再进行垃圾回收

这里 Golang 使用的是基于 标记-清除 法的三色标记算法

GC触发条件

一般来说有三种情况会触发GC

  1. 辅助GC,在分配内存时,会判断当前的Heap内存分配量是否达到了触发GC的阈值,如果超过了阈值则启动一轮GC
  2. 调用 systeme.GC() 来强制启动一轮GC
  3. 当超过一定时间未运行GC的情况下会执行GC

为什么需要三色标记算法

相比之前的标记清除算法,其GC执行期间需要把整个程序完全暂停,不能异步执行GC操作。对实时性要求比较高的系统来说,这种需要长时间挂起的标记清除算法是不可接受的,而三色标记算法就很好的解决了这个问题。 三色标记最大的好处是可以异步执行,从而可以以中断时间极少的代价或者完全没有中断操作来进行整个GC。

三色指的是黑色、灰色、白色,

  1. 黑色:根对象,或者某对象和它的子对象都被扫描过
  2. 灰色:某对象被扫描过,但是子对象未被扫描
  3. 白色:未被扫描的对象,如果扫描完成所有对象之后,最终白色为不可达对象,即垃圾对象

所谓的读写屏障就是针对某个对象变量赋值、读取时做一些格外的操作

垃圾回收的主要流程

  1. 初始化所有对象被标记为白色
  2. 从root开始找到所有可达对象,标记为灰色,放入到待处理队列中
  3. 遍历灰色对象队列,把其引用的对象标记为灰色放入到待处理队列中,自身标记为黑色
  4. 处理完灰色对象队列,知道没有灰色对象为止
  5. 其余白色为垃圾对象,执行清扫工作

三色标记法的引用消失问题

什么是引用消失:即原本应该是黑色的对象被误标为白色。

发生的条件

当且仅当一下两个条件同时满足的时候

  1. 赋值器插入了一条或多条从黑色对象到白色对象的新引用
  2. 赋值器删除了全部从灰色对象到该白色对象的直接或间接引用。

只需要破坏成立的条件即可,有两种方案:增量更新和原始快照

  1. 增量更新,当一个白色对象被黑色对象引用时,把黑色对象重新标记为灰色,让垃圾回收算法重新扫描即可
  2. 原始快照:原始快照要破坏的是第二个条件,当灰色对象要删除白色对象的引用关系时,就将这个要删除的引用记录下来,在并发扫描结束之后,再扫描这些灰色节点

原始快照关注的是引用删除,增量更新关注的是引用增加

因为增量更新算法还需要把原本为黑色的节点再次扫描一遍,效率有点低下

2021-07-13 14:59

哈哈哈,今天并没有日志


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK