Golang——垃圾回收GC
- 引用计数:对每个对象维护一个引用计数,当引用该对象的对象被销毁时,引用计数减1,当引用计数器为0是回收该对象。
- 优点:对象可以很快的被回收,不会出现内存耗尽或达到某个阀值时才回收。
- 缺点:不能很好的处理循环引用,而且实时维护引用计数,有也一定的代价。
- 代表语言:Python、PHP、Swift
- 标记-清除:从根变量开始遍历所有引用的对象,引用的对象标记为"被引用",没有被标记的进行回收。
- 优点:解决了引用计数的缺点。
- 缺点:需要STW,即要暂时停掉程序运行。
- 代表语言:Golang(其采用三色标记法)
- 分代收集:按照对象生命周期长短划分不同的代空间,生命周期长的放入老年代,而短的放入新生代,不同代有不能的回收算法和回收频率。
- 优点:回收性能好
- 缺点:算法复杂
- 代表语言: JAVA
标记
在之前的Go语言——内存管理一文中,分析过span是内存管理的最小单位,所以猜测gc的粒度也是span。
type mspan struct {
// allocBits and gcmarkBits hold pointers to a span's mark and
// allocation bits. The pointers are 8 byte aligned.
// There are three arenas where this data is held.
// free: Dirty arenas that are no longer accessed
// and can be reused.
// next: Holds information to be used in the next GC cycle.
// current: Information being used during this GC cycle.
// previous: Information being used during the last GC cycle.
// A new GC cycle starts with the call to finishsweep_m.
// finishsweep_m moves the previous arena to the free arena,
// the current arena to the previous arena, and
// the next arena to the current arena.
// The next arena is populated as the spans request
// memory to hold gcmarkBits for the next GC cycle as well
// as allocBits for newly allocated spans.
//
// The pointer arithmetic is done "by hand" instead of using
// arrays to avoid bounds checks along critical performance
// paths.
// The sweep will free the old allocBits and set allocBits to the
// gcmarkBits. The gcmarkBits are replaced with a fresh zeroed
// out memory.
allocBits *gcBits
gcmarkBits *gcBits
}
如图所示,通过gcmarkBits位图标记span的块是否被引用。对应内存分配中的bitmap区。
三色标记
- 灰色:对象已被标记,但这个对象包含的子对象未标记
- 黑色:对象已被标记,且这个对象包含的子对象也已标记,gcmarkBits对应的位为1(该对象不会在本次GC中被清理)
- 白色:对象未被标记,gcmarkBits对应的位为0(该对象将会在本次GC中被清理)
例如,当前内存中有A~F一共6个对象,根对象a,b本身为栈上分配的局部变量,根对象a、b分别引用了对象A、B, 而B对象又引用了对象D,则GC开始前各对象的状态如下图所示:
- 初始状态下所有对象都是白色的。
- 接着开始扫描根对象a、b; 由于根对象引用了对象A、B,那么A、B变为灰色对象,接下来就开始分析灰色对象,分析A时,A没有引用其他对象很快就转入黑色,B引用了D,则B转入黑色的同时还需要将D转为灰色,进行接下来的分析。
- 灰色对象只有D,由于D没有引用其他对象,所以D转入黑色。标记过程结束
- 最终,黑色的对象会被保留下来,白色对象会被回收掉。

STW
stop the world是gc的最大性能问题,对于gc而言,需要停止所有的内存变化,即停止所有的goroutine,等待gc结束之后才恢复。
触发
- 阈值:默认内存扩大一倍,启动gc
- 定期:默认2min触发一次gc,src/runtime/proc.go:forcegcperiod
- 手动:runtime.gc()
go
- Sweep Termination: 对未清扫的span进行清扫, 只有上一轮的GC的清扫工作完成才可以开始新一轮的GC
- Mark: 扫描所有根对象, 和根对象可以到达的所有对象, 标记它们不被回收
- Mark Termination: 完成标记工作, 重新扫描部分根对象(要求STW)
- Sweep: 按标记结果清扫span
目前整个GC流程会进行两次STW(Stop The World), 第一次是Mark阶段的开始, 第二次是Mark Termination阶段.
- 第一次STW会准备根对象的扫描, 启动写屏障(Write Barrier)和辅助GC(mutator assist).
- 第二次STW会重新扫描部分根对象, 禁用写屏障(Write Barrier)和辅助GC(mutator assist).
需要注意的是, 不是所有根对象的扫描都需要STW, 例如扫描栈上的对象只需要停止拥有该栈的G.
从go 1.9开始, 写屏障的实现使用了Hybrid Write Barrier, 大幅减少了第二次STW的时间.
写屏障
因为go支持并行GC, GC的扫描和go代码可以同时运行, 这样带来的问题是GC扫描的过程中go代码有可能改变了对象的依赖树。
例如开始扫描时发现根对象A和B, B拥有C的指针。
- GC先扫描A,A放入黑色
- B把C的指针交给A
- GC再扫描B,B放入黑色
- C在白色,会回收;但是A其实引用了C。
为了避免这个问题, go在GC的标记阶段会启用写屏障(Write Barrier).
启用了写屏障(Write Barrier)后,
- GC先扫描A,A放入黑色
- B把C的指针交给A
- 由于A在黑色,所以C放入灰色
- C没有子对象,放入黑色
- 扫描B,B没有子对象,放入黑色
即使A可能会在稍后丢掉C, 那么C就在下一轮回收。
开启写屏障之后,当指针发生改变, GC会认为在这一轮的扫描中这个指针是存活的, 所以放入灰色。
root
首先标记root跟对象,根对象的子对象也是存活的。
根对象包括:全局变量,各个G stack上的变量等。
Golang——垃圾回收GC的更多相关文章
- Golang——垃圾回收GC(2)
1 垃圾回收中的重要概念 1.1 定义 In computer science, garbage collection (GC) is a form of automatic memory manag ...
- golang 垃圾回收 gc
http://ruizeng.net/golang-gc-internals/ 摘要 在实际使用go语言的过程中,碰到了一些看似奇怪的内存占用现象,于是决定对go语言的垃圾回收模型进行一些研究.本文对 ...
- 【GoLang】golang垃圾回收 & 性能调优
golang垃圾回收 & 性能调优 参考资料: 如何监控 golang 程序的垃圾回收_Go语言_第七城市 golang的垃圾回收(GC)机制 - 两只羊的博客 - 博客频道 - CSDN.N ...
- golang垃圾回收
常见GC算法 我总结了一下常见的 GC 算法.分别是:引用计数法.Mark-Sweep法.三色标记法.分代收集法. 1. 引用计数法 原理是在每个对象内部维护一个整数值,叫做这个对象的引用计数,当对象 ...
- 从C#垃圾回收(GC)机制中挖掘性能优化方案
GC,Garbage Collect,中文意思就是垃圾回收,指的是系统中的内存的分配和回收管理.其对系统性能的影响是不可小觑的.今天就来说一下关于GC优化的东西,这里并不着重说概念和理论,主要说一些实 ...
- 垃圾回收GC:.Net自己主动内存管理 上(一)内存分配
垃圾回收GC:.Net自己主动内存管理 上(一)内存分配 垃圾回收GC:.Net自己主动内存管理 上(一)内存分配 垃圾回收GC:.Net自己主动内存管理 上(二)内存算法 垃圾回收GC:.Net自己 ...
- Java 垃圾回收(GC) 泛读
Java 垃圾回收(GC) 泛读 文章地址:https://segmentfault.com/a/1190000008922319 0. 序言 带着问题去看待 垃圾回收(GC) 会比较好,一般来说主要 ...
- 类装饰器,元类,垃圾回收GC,内建属性、内建方法,集合,functools模块,常见模块
'''''''''类装饰器'''class Test(): def __init__(self,func): print('---初始化---') print('func name is %s'%fu ...
- 性能测试三十五:jvm垃圾回收-GC
垃圾回收-GC 三个问题 哪些内存需要回收? 什么时候回收? 如何回收? YoungGC和FullGC: 新生代引发的GC叫YoungGC 老年代引发的GC叫FullGC FullGC会引起整个Jvm ...
随机推荐
- [转] 理解 JavaScript 中的 Array.prototype.slice.apply(arguments)
假如你是一个 JavaScript 开发者,你可能见到过 Array.prototype.slice.apply(arguments) 这样的用法,然后你会问,这么写是什么意思呢? 这个语法其实不难理 ...
- asp.net core session的使用
Session介绍 本文假设读者已经了解Session的概念和作用,并且在传统的.net framework平台上使用过. Asp.net core 1.0好像需要单独安装,在nuget控制台,选择你 ...
- Python dict get items pop update
一.get方法 dict = {'k1':1,'k2':2} dict.get('k1') 1 dict.get('k2') 2 dict.get('k3') None dict.get('k3',' ...
- streaming优化:spark.streaming.receiver.maxRate
使用spark.streaming.receiver.maxRate来限制你的吞吐的最大信息量. 因为当streaming程序的数据源的数据量突然变大巨大,可能会导致streaming被撑住导致吞吐不 ...
- ubuntu TensorFlow安装
Tensorflow安装确实比caffe简单... cuda,cudnn安装就不说了 1 安裝pip(有就跳过) sudo apt-get install python-pip python-dev ...
- P2393 yyy loves Maths II
P2393 yyy loves Maths IIlong double比如保留5位小数*1000000都变成整数最后再/1000000避免精度误差scanf("%Lf",& ...
- python+imageMagick写的一个压缩图片脚本
!/usr/bin/python import os import cPickle as p import re import Image def imageCompre(imagedir = '.' ...
- Web大前端面试题-Day10
1. px和em的区别? px和em都是长度单位; 区别是: px的值是固定的,指定是多少就是多少, 计算比较容易. em得值不是固定的,并且em会继承父级元素的字体大小. 浏览器的默认字体高都是16 ...
- Progressive web app理念及发展前景
前一段时间微信推出微信小程序进行公测,着实火了一把,博得了大众的眼球,不明真相的吃瓜观众们纷纷围观,所谓的“微信小程序”,通俗的讲就是一种不需要下载安装即可使用的应用程序,脱离于app商店依托于浏览器 ...
- Vijos.lxhgww的奇思妙想(k级祖先 长链剖分)
题目链接 https://blog.bill.moe/long-chain-subdivision-notes/ http://www.cnblogs.com/zzqsblog/p/6700133.h ...