GO的GC辣鸡回收(一)
用户程序通过内存分配器(Allocator)在堆上申请内存,而垃圾收集器(Collector)负责回收堆上的内存空间,内存分配器和垃圾收集器共同管理程序中的堆内存空间。
基本概念
垃圾分类
- 语义垃圾:也就是内存泄漏,指的是从语法上可达的对象,也就是被其他对象引用的,但是从语义上来讲是垃圾。这类垃圾,垃圾回收是不管的
- 语法垃圾:从语法上是不可达的对象,也就是没有对象引用了,这些垃圾是垃圾回收重点照顾的对象
垃圾回收算法
常见的垃圾回收算法:
引用计数:

某个对象的根引用计数变为0时,其所有节点均需被回收
标记压缩:

将存活对象移动到一起,有效解决内存碎片问题
复制算法:

将所有正在使用的对象从From空间复制到To空间,堆利用率只有一半,也能解决内存碎片问题
标记清除:

标记垃圾对象,然后再清除。解决不了内存碎片问题,需要与能尽量避免内存碎片的内存分配器使用,如tcmalloc
标记清除
标记清除算法是最常见的垃圾收集算法,标记清除收集器是跟踪式垃圾收集器,其执行过程可以分为标记、清除两个阶段:
- 标记阶段:从根对象出发查找并标记堆中所有存活的对象
- 清除阶段:遍历堆中的全部对象,回收未被标记的垃圾对象并将回收的内存加入空闲链表
传统的标记清除算法,垃圾收集器从垃圾收集的根对象出发,递归遍历这些对象指向的子对象并将所有可达的对象标记成存活。标记结束后,垃圾收集器会依次遍历堆中的对象并清除其中的垃圾,整个过程需要标记对象的存活状态,所以用户程序在垃圾收集的过程中不能执行,也就是常说的STW(Stop The World)。
三色抽象
为了解决原始标记清除算法带来的长时间STW,大部分追踪式垃圾收集器都会实现三色标记算法的变种以缩短STW的时间
三色标记算法将程序中的对象分成白色、黑色、灰色:
- 白色对象:潜在的垃圾,也就是没有被扫到的对象,其内存可能会被垃圾收集器回收
- 黑色对象:活跃的对象,包括不存在任何引用外部指针的对象以及从根对象可达的对象
- 灰色对象:活跃的对象,因为存在指向白色对象的外部指针,垃圾收集器会扫描这些对象的子对象
标记过程:
垃圾收集器开始工作的时候,不存在任何黑色对象,根对象会被标记成灰色,垃圾收集器只会从灰色对象集合中取出对象开始扫描,当灰色集合中不存在任何对象时,标记就会结束。

大致工作原理:
- 从灰色对象的集合中选择一个灰色对象并将其标记成黑色
- 将黑色对象指向的所有对象都标记成灰色,保证该对象和被该对象引用的对象都不会被回收
- 重复上述两个步骤直到不存在灰色对象
当三色标记结束后,应用程序的堆中就不存在任何灰色对象,我们只能看到黑色的存活对象以及白色的垃圾对象,垃圾收集器可以回收这些白色的垃圾。
缺陷:
由于用户程序可能在标记执行的过程中修改对象的指针,所以三色标记清除算法本身是不可以并发或者增量执行的,仍需要STW。如果本来不应该被回收的对象被回收了,这在内存管理中是非常严重的错误,这种错误称为悬挂指针,也就是指针没有指向特定类型的合法对象,影响了内存的安全性,想要并发或者增量标记对象就需要使用屏障技术。
屏障技术
内存屏障技术是一种屏障指令,可以让CPU或编译器在执行内存相关的操作时遵循特定的约束,目前多数的现代处理器都会乱序执行指令以最大化性能,但是该技术能够保证内存操作的顺序性,在内存屏障前执行的操作一定会先于内存屏障后执行的操作。想在并发或增量的标记算法中保证正确性,需要达到两种三色不变性的其中一种。
三色不变性:
- 强三色不变性:黑色对象不会指向白色对象,只会指向灰色对象或者黑色对象
- 弱三色不变性:黑色对象指向的白色对象必须包含一条从灰色对象经由多个白色对象的可达路径
屏障技术分为读屏障和写屏障,但是由于读屏障需要在读操作中加入代码片段,所以对用户程序的性能影响较大。解析一下go语言中使用的两种写屏障技术,插入写屏障和删除写屏障。
插入写屏障(DIJKSTRA)
writePointer(slot, ptr):
shade(ptr)
*slot = ptr
每当要执行*slot = ptr时,会先执行写屏障通过shade函数尝试改变指针颜色。如果ptr指针是白色,那么会将该对象设置成灰色。

这张图中可以看到,在一次正常的标记过程中,发生了用户程序修改了指针引用(或者新插入了一个引用关系)的情况,如果我们采用 插入写屏障 我们就需要将新指向的对象标为灰色,以此保证强三色不变性。(对于新指向的对象来说,属于被插入一个引用,所以叫插入写屏障)
在插入写屏障中,我们的标记过程变成(关键第2步):
- 基本标记流程不变,我们快进到垃圾收集器将根对象指向A对象标记成黑色,并将A对象指向的对象B标记成灰色。
- 这时用户程序修改A对象的指针,将原本A对象指向B对象的指针指向C对象,这个时候就会触发写屏障将C对象标记为灰色,避免被错误回收。
- 垃圾收集器依次遍历程序中的其他灰色对象,将他们分别标记成黑色
删除写屏障(YUASA)
writePointer(slot, ptr)
shade(*slot)
*slot = ptr
删除写屏障会在老对象的引用被删除的时候,将白色的老对象涂成灰色,这样就可以保证弱三色不变性,老对象引用的下游对象一定可以被灰色对象引用。

使用删除写屏障技术的垃圾收集器和用户程序交替运行的场景中的标记过程:
- 垃圾收集器将根对象指向A对象标记成黑色并将A对象指向的对象B标记成灰色
- 如果这时用户程序将B指向C的指针删除,那么C触发删除写屏障,由于C是白色,所以被涂成灰色
- 垃圾收集器依次遍历程序中的其他灰色对象,将他们分别标记成黑色
第二步触发删除写屏障的着色,因为删除了B指向C的指针,所以C和D分别违反强三色不变性和弱三色不变性,着色后保证了三色不变性,避免悬挂指针。
简单来说就是,在改变指针指向的时候,原来指向的那个对象是白色的话就要变成灰色,以此保证弱三色不变性。(对于老对象来说,引用关系被解除了,所以叫删除写屏障)
增量和并发
两种策略优化垃圾收集器不会以为回收垃圾导致长时间STW:
- 增量垃圾收集:增量得标记和清除垃圾,降低应用程序暂停的最长时间
- 并发垃圾手机:利用多核的计算资源,在用户程序执行时并发标记和清除垃圾
由于两种方式都需要垃圾收集器与用户程序交替执行,所以需要配合屏障技术。
增量收集器
增量收集器将原本时间较长的暂停时间切分成多个更小的GC时间片。增量收集器需要配合三色标记法和屏障技术一起使用。将GC过程分段执行,虽然拉长了总的垃圾回收时间,但是减少了程序STW的时间。不过写屏障还是有些开销的。
并发收集器
利用多核优势,将GC过程与用户程序并行执行(大部分情况下),也是要配合屏障技术。
References
- https://draveness.me/golang/docs/part3-runtime/ch07-memory/golang-garbage-collector/
- https://spin.atomicobject.com/2014/09/03/visualizing-garbage-collection-algorithms/
GO的GC辣鸡回收(一)的更多相关文章
- JVM 辣鸡回收
垃圾回收算法 标记清除法 先标记出需要回收的对象,然后一次性回收.缺点:会产生内存碎片,并且效率也不高. 标记压缩法 先标记出需要回收的对象,然后让存活对象向一端移动,移动的过程中进行回收辣鸡.避免了 ...
- JVM学习(4)——全面总结Java的GC算法和回收机制
俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习!涉及到的知识点总结如下: 一些JVM的跟踪参数的设置 Java堆的分配参数 -Xmx 和 –Xms 应该保持一个什么关系,可以让系统的 ...
- java: system.gc()和垃圾回收机制finalize
System.gc()和垃圾回收机制前的收尾方法:finalize(收尾机制) 程序退出时,为每个对象调用一次finalize方法,垃圾回收前的收尾方法 System.gc() 垃圾回收方法 clas ...
- 关于GC进行垃圾回收的时机
前言 今天查看一个同事的代码,发现代码中多处地方使用了GC.Collect()方法,我问他为什么这么做,他说感觉程序中定义了好多变量,怕GC回收不及时,用GC.Collect()可以手动掌控GC进行垃 ...
- GC(垃圾回收)
Java程序的内存分配和回收都是由JRE在后台自动进行的.JRE会负责回收那些不再使用的内存,这种机制被称为垃圾回收GC.通常JRE会提供一条超级线程来进行检测和控制,一般都是在CPU空闲或内存不足时 ...
- 【转载】Java性能优化之JVM GC(垃圾回收机制)
文章来源:https://zhuanlan.zhihu.com/p/25539690 Java的性能优化,整理出一篇文章,供以后温故知新. JVM GC(垃圾回收机制) 在学习Java GC 之前,我 ...
- JVM总括二-垃圾回收:GC Roots、回收算法、回收器
JVM总括二-垃圾回收:GC Roots.回收算法.回收器 目录:JVM总括:目录 一.判断对象是否存活 为了判断对象是否存活引入GC Roots,如果一个对象与GC Roots没有直接或间接的引用关 ...
- JVM学习(4)——全面总结Java的GC算法和回收机制---转载自http://www.cnblogs.com/kubixuesheng/p/5208647.html
俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习!涉及到的知识点总结如下: 一些JVM的跟踪参数的设置 Java堆的分配参数 -Xmx 和 –Xms 应该保持一个什么关系,可以让系统的 ...
- Java性能优化之JVM GC(垃圾回收机制)
Java的性能优化,整理出一篇文章,供以后温故知新. JVM GC(垃圾回收机制) 在学习Java GC 之前,我们需要记住一个单词:stop-the-world .它会在任何一种GC算法中发生.st ...
随机推荐
- gitbook导出markdown文件为pdf格式
前言本人想完成如题所示的操作,可是兜兜转转在网上搜了好久,不是Linux下的教程就是mac OS下的教程,而且一大堆windows的教程能够说明白的寥寥无几,本着分享的态度,鄙人今天特整理教程如下: ...
- SpringMVC 参数中接收之一 List
作者:张艳涛 time:2020-07-31 SpingMVC 一.前台传数组,SpingMVC用addusers(@RequestBody List<UserPojo> userlist ...
- 2020年度钻石C++C学习笔记(3)--《博学谷》
1.Unix/Linux操作系统介绍 1.1 操作系统的作用 1.1.1 操作系统的目标 l 方便:使计算机系统易于使用 l 有效:以更有效的方式使用计算机系统资源 l 扩展:方便用户有效开发.测试和 ...
- GooseFS助力大数据业务数倍提升计算能力
前言 GooseFS是由腾讯云推出的一款分布式缓存方案,主要针对包括需要缓存加速的数据湖业务场景,提供基于对象存储COS服务的近计算端数据加速层. GooseFS 基于开源大数据缓存方案 Alluxi ...
- nmap工具使用随笔
1.nmap主要用途:主机发现,端口扫描,版本检测,os检测 2.Nmap是Linux下的网络扫描和嗅探工具包,它可以扫描大型的网络,获取那台主机正在运行以及提供的服务等信息. 3.nmap语法格式: ...
- 为数不多的人知道的 Kotlin 技巧及解析
文章中没有奇淫技巧,都是一些在实际开发中常用,但很容易被我们忽略的一些常见问题,源于平时的总结,这篇文章主要对这些常见问题进行分析. 这篇文章主要分析一些常见问题的解决方案,如果使用不当会对 性能 和 ...
- 《手把手教你》系列技巧篇(十八)-java+ selenium自动化测试-元素定位大法之By css中卷(详细教程)
1.简介 按计划今天宏哥继续讲解倚天剑-css的定位元素的方法:ID属性值定位.其他属性值定位和使用属性值的一部分定位(这个类似xpath的模糊定位). 2.常用定位方法(8种) (1)id(2)na ...
- 【笔记】Stacking方法
Stacking 先前学习的集成学习 先前的思路很简单,假设有三个算法,每个算法都对数据进行一个预测,最后综合这三个结果得出一个最终结果,对于分类问题可以进行少数服从多数,对于回归问题可以简单地取平均 ...
- 值得收藏 | 深度剖析 TensorCore 卷积算子实现原理
作者:章晓 | 旷视 MegEngine 架构师 一.前言 2020 年 5 月 Nvidia 发布了新一代的 GPU 架构安培(Ampere).其中和深度学习关系最密切的莫过于性能强劲的第三代的 T ...
- SpringBoot - 集成Auth0 JWT
目录 前言 session认证与Token认证 session认证 Token认证 JWT简介 JWT定义 JWT数据结构 JWT的类库 具体实现 JWT配置 JWT工具类 测试接口 前言 说说JWT ...