-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Golang GC流程(为什么/为什么不) #46
Comments
Yuasa的删除写屏障则需要在GC开始时STW扫描堆栈来记录初始快照,这个过程会保护开始时刻的所有存活对象 |
这个地方我也是找了很多资料也没看懂,只能人云亦云 |
@rick-max 之前有说过Dijkstra的实现是不对栈上的指针做操作(防止灰色对象大量膨胀),所以Yuasa的实现也是不对栈上的对象做操作,所以嘛要在开始的时候保护栈,而dijkstra是结束的时候保护。。。这个是我同事告诉我的 |
Go Garbage Collection
Go语言的选择,优势缺点
Go GC 流程(基于go1.13) 无法复制加载中的内容
以下程序go1.14之前会退出吗?
答案是不会, 因为要先暂停所有的goroutine。 但是go1.14就可以解决(异步抢占) 写屏障 go1.5 Dijkstra 插入写屏障
优点:
插入写屏障需要重新扫描栈,删除写屏障不能防止指针从栈里被隐藏到黑色的堆区对象里,需要一开始stw扫描栈 Golang中的混合写屏障满足的是变形的弱三色不变式,同样允许黑色对象引用白色对象,白色对象处于灰色保护状态,但是只由堆上的灰色对象保护。由于结合了Yuasa的删除写屏障和Dijkstra的插入写屏障的优点,只需要在开始时并发扫描各个goroutine的栈,使其变黑并一直保持,这个过程不需要STW,而标记结束后,因为栈在扫描后始终是黑色的,也无需再进行re-scan操作了,减少了STW的时间。 GC 调试
演进和总结
Ref: |
Golang GC流程(为什么/为什么不)
介绍
中文最好的解释
什么时候触发GC
什么是根
是一个有限的指针集合,程序可不经过其他对象直接访问这些指针,堆中的对象被加载时,需要先加载根中的指针。在Go中,一般为goroutine自己的栈空间和全局栈空间。
屏障
本来是灰色的B指向C, 但是我们还没有扫描B的时候, C被改指向A, 但是A已经是黑色的了, 那么现在黑色的指向一个白色的对象且没有任何灰色的对象指向白色的对象. 这时白色的对象无论如何都不会被访问到.
当回收器满足下面两种情况之一时,即可保证不会出现对象丢失问题。
弱三色不变式:所有被黑色对象引用的白色对象都处于灰色保护状态(直接或间接从灰色对象可达)。 强三色不变式:不存在黑色对象到白色对象的指针。
强三色不变式很好理解,强制性的不允许黑色对象引用白色对象即可。而弱三色不变式中,黑色对象可以引用白色对象,但是这个白色对象仍然存在其他灰色对象对它的引用,或者可达它的链路上游存在灰色对象。
实现
知乎R大对go GC的评价
R大的文章解决了三个认知问题
GO的GC算什么系列的, 其他语言有类似的实现吗?
跟Java的CMS GC很像. 都是基于增量的写屏障的保证下的并发标记清楚机制.
如果有那么他们的流程是什么样子的, 各自有哪些优化?
核心流程一样,GO还有很多优化(比如不需要全部扫描栈), 但是也少了在re-marking之前试图重新标记的优化
GO GC优势是什么, 劣势是什么?
最大限度的减少了
STW
, 但是会长时间占用CPU, 吞吐量上不去. 同时因为Go大量的struct都是创建在goroutine的栈上的, 所以创建新对象的数量是没有Java那么多的.Go的
CMS GC
其实与HotSpot VM
的CMS GC
相比是非常相似的。都是只基于incremental update
系write-barrier
的Mostly-Concurrent Mark-Sweep
。两者的工作流程中最核心的步骤都是:两者的(1)都是
stop-the-world
的,这是两者的GC暂停的主要来源之一。 HotSpot VM的CMS GC的(3)也是stop-the-world
的,而且这个暂停还经常比(1)的暂停时间要更长;Go 1.6 CMS GC则在此处做了比较细致的实现,尽可能只一个个goroutine暂停而不全局暂停----只要不是全局暂停都不算在用户关心的"暂停时间"里,这样Go版就比HotSpot版要做得好了。HotSpot版CMS对(3)的细化优化是,在真正进入stop-the-world的re-marking之前,先尝试做一段时间的所谓并发的"abortable concurrent pre-cleaning",尝试并发的追赶应用程序对引用关系的改变,以便缩短re-marking的暂停时间。不过这里实现得感觉还不够好,还可以继续改进的。
有个有趣的细节,Go版CMS在(3)中重新扫描goroutine的栈时,只需要扫描靠近栈顶的部分栈帧,而不需要扫描整个栈----因为远离栈顶的栈帧可能在(2)的过程中根本没改变过,所以可以做特殊处理;HotSpot版CMS在(3)中扫描栈时则需要重新扫描整个栈,没抓住机会减少扫描开销。Go版CMS就是在众多这样的细节上比HotSpot版的更细致。
再举个反过来的细节。目前HotSpot VM里所有GC都是分代式的,CMS GC在这之中属于一个old gen GC,只收集old gen;与其配套使用的还有专门负责收集young gen的Parallel New GC(ParNew),以及当CMS跟不上节奏时备份用的full GC。分代式GC很自然的需要使用write barrier,而CMS GC的concurrent marking也需要write barrier。HotSpot VM就很巧妙的把这两种需求的write barrier做在了一起,共享一个非常简单而高效的write barrier实现。 Go版CMS则需要在不同阶段开启或关闭write barrier,实现机制就会稍微复杂一点点,write barrier的形式也稍微慢一点点。
从效果看Go 1.6的CMS GC做得更好,但HotSpot VM的CMS GC如果有更多投入的话也完全可以达到一样的效果;并且,得益于分代式GC,HotSpot VM的CMS GC目前能承受的对象分配速度比Go的更高,这算是个优势。
The text was updated successfully, but these errors were encountered: