zoukankan      html  css  js  c++  java
  • 浅谈Golang中的垃圾回收机制?

    垃圾回收(GC)是在后台运行一个守护线程,它的作用是在监控各个对象的状态,识别并且丢弃不再使用的对象来释放和重用资源。Golang底层采用标记-清除算法,简单描述就是先标记,再清除(清除涉及stw)

    Golang采用三色标记法是对标记阶段的改进

    简单的标记-清除会有stw,三色标记通过将扫描的对象分为三个阶段,避免了stw,其中三色分别对应的状态为:

    • 灰色:对象还在标记队列中等待
    • 黑色:对象已被标记,gcmarkBits对应的位为1(对象不会在本次GC中被清理)
    • 白色:对象未被标记,gcmarkBits对应的位为0(对象将会在本次GC中被清理)

    三色处理步骤:

    1. 初始状态下所有对象都是白色的。
    2. 首先标记root对象为灰色,放入待处理队列。
    3. 取出待处理队列的灰色对象,将其引用标记为灰色,放入待处理队列,并将本身标记为黑色.
    4. 循环第三步,直到待处理队列为空(在标记过程中的新的引用对象,通过写屏障直接标记为灰色),此时剩下的只有白色和黑色,白色对象则表示不可达,将其清理.

    Golang的垃圾回收中,从理论上是应该没有stw阶段的,但在实际中会出现GC扫描时内存变化(用户线程导致)的混乱,可能导致一些本不该被回收的对象被回收了或者应该被回收的对象还存在,stw不能停,于是Golang底层采用了 写屏障 和 辅助GC 来优化垃圾回收。

    垃圾回收时出现的内存混乱的情况:

    垃圾回收器的正确性体现在:不应出现对象的丢失,也不应错误的回收还不需要回收的对象。 作为内存屏障的一种,写屏障(Write Barrier)是一个在并发垃圾回收器中才会出现的概念。

    当以下条件同时满足会破坏垃圾回收器正确性:

    1. 赋值器修改对象图,导致某一黑色对象引用白色对象。

    2.白色对象的所有和他存在可达关系的灰色对象都丢失了访问它的可达路径。(当一个白色对象没有被任何灰对象指向时,就默认满足条件2了,如果这个时候一个黑色对象指向它就一定会出错)

    当1,2条件都不满足时,称为强三色不变性,黑色对象永远不会指向白色对象

    当只满足条件1时,称为弱三色不变性,黑色对象指向的白色对象至少包含一条从灰色对象到达它的可达路径

    Dijkstra插入写屏障(避免条件1)

    一个对象可以存储在栈空间也可以存储在堆空间,栈空间容量小且对速度要求更高,因此写屏障仅仅存在于堆空间,就是堆空间黑色对象重新引用的对象被直接标为灰对象,对于栈空间黑色对象重新引用的对象则需要在stw阶段重新扫描一遍栈空间,直到灰色队列为空。

    Yuasa删除写屏障(避免条件2)

    其思想是当赋值器从灰色或白色对象中删除白色指针时,通过写屏障将这一行为通知给并发执行的回收器。当用户程序出现灰色对象到白色对象的路径断开时,就直接触发删除写屏障把这个白色对象变为灰色这样就不会导致这个对象被回收了

    Dijkstra插入写屏障会在一轮扫描结束以后STW对栈空间重新扫描,当Groutine过多时,STW就非常影响程序性能;另外就是插入写屏障可能引入一些无用对象在下一轮垃圾回收时被回收

    Yuasa删除写屏障会导致导致回收效率降低,可能导致大量无用对象下一轮才会被回收

    因此引入混合写屏障

    具体步骤如下:

    • GC开始时将栈上所有对象标记为黑色,无须STW
    • GC期间在栈上创建的新对象均标记为黑色(避免了Dijkstra插入写屏障一轮扫描之后的STW)
    • 将被删除的下游对象标记为灰色 (这个难道不是也会导致有的对象这一轮无法被回收吗?)
    • 将被添加的下游对象标记为灰色

    GC触发的时机

    每次内存分配时检查当前内存分配量是否已达到阈值(环境变量GOGC):默认100%,即当内存扩大一倍时启用GC

    定时触发:当最近2分钟未触发过GC时,会触发一次GC

    通过runtime.GC()手动触发

    GC的优化

    分配的对象越多,GC性能就越差,所以需要减少对象分配的个数,比如对象复用,使用sync.Pool 

  • 相关阅读:
    深入理解JVM(5)——垃圾收集和内存分配策略
    深入理解JVM(4)——对象的创建和访问
    深入理解JVM(3)——类加载机制
    深入理解JVM(2)——运行时数据区
    深入理解JVM(1)——栈和局部变量操作指令
    文本对比
    LRUCache
    linux服务器间文件夹拷贝
    java实现sftp客户端上传文件夹的功能
    sopUI上手教程
  • 原文地址:https://www.cnblogs.com/peterleee/p/14232762.html
Copyright © 2011-2022 走看看