如果实现了一种不用暂停世界的GC算法,会对现在编程语言产生什么影响?

目前主流行的高级语言GC方法都是通过可达性判断来实现的。这种算 法有个缺点,在回收内存时需要暂停工作线程。 本人实现了一套不用暂停时间的gc的方法,大…
关注者
273
被浏览
116,265
登录后你可以
不限量看优质回答私信答主深度交流精彩内容一键收藏

回答时题目为

如果实现了一种不用暂停世界的GC算法,会对现在编程语言产生什么影响?

不会怎么样。早在15年前 Azul 就在 JVM 上实现了 Pauseless Garbage Collection,这时 JVM 在 GC 时就几乎不需要停下来了,

而十年前的 Zing JVM 更是搭载了怪物级的 C4 GC 算法——原理上无暂停时间为了方便实现所以还是采用了一定的极短暂停,但只要有需要就可以去除),从 mark 到回收全程并发,兼顾了吞吐量,且能轻松应对极端情况下的内存分配(2TB 堆内存外挂 10TB 堆外内存的情况下依然轻松维持在< 5ms的暂停时间)。

至于 OpenJDK 虽然拉跨点,但也实现了类似 PGC 类似的低暂停 GC 算法,也就是 ZGC,在 JDK 16 中已经做到了最大暂停时间保证在 1ms 以下,平均暂停时间通常为 0.05ms 左右,最大暂停时间通常为 0.5ms,暂停时间与堆大小、栈大小、线程数等几乎无关。

在现在,主流 GC 语言中不少都实现了几乎无暂停这个目标,先进一些的就是实现全并发的 Tracing GC,拉跨一些的(譬如 CPython)接近你所描述的算法,用 RC+Tracing GC 实现的。

至于“真正”完全无暂停时间相比“几乎”无暂停时间有多大优势呢……看看R大所说的 C4 GC 暂时没有完全去除暂停的理由

C4算法虽然可以是完全并发的,但目前Zing JVM里的实现还是采用了若干短暂的暂停,方便实现——只要有需要我们可以把这些暂停都去掉,达到算法上所描述的完全并发。之所以目前还没强烈的感受到去掉这些通常< 10ms的暂停的需要,是因为我们发现Linux自身就经常会带来一些> 10ms的停顿,也就是说Zing的GC暂停已经在许多实际部署的Linux环境的自身系统的噪音级别以下了。

我看了一眼你的文章,你对现代 GC 的误解很重:

引用计数和你所说的“高效”恰恰相反,引用计数效率很低,反复增减计数器是很重的、无法并行化的开销,严重影响了回收的吞吐量,通常来说基于可达性分析的Tracing GC才是高效的一方,你的算法结合了 RC 的低效和并发 GC 算法 GC 线程的额外负载,嗯……

你认为的“运行算法时必须暂停运行工作线程的运行”也是错误,反例已经说过了,另外虽然这些算法的实现因为各种原因保留了一定的暂停时间,但这些低暂停 GC 回收过程也是完全并发不需要 STW,STW 通常是在扫描 gcroot 等过程中。

自己钻研是好事,不过闭门造车实在不可取,搜索一下 Golang 采用的三色标记算法以及 PGC/ZGC 相关的资料,相信会对你有不少帮助。


看到了题目更新了,我写回答的时候题目是“如果实现了一种不用暂停世界的GC算法,会对现在编程语言产生什么影响?”,所以我更多的和 Java 等有全局 GC 的语言对比,认为题主的算法价值不高,

不过和题主交流后知道题主想实现的是作为 C++ 的 GC 库,我觉得有一定的价值,但是要注意,题主的算法处于这样的夹缝中:

对于无循环引用,或者所有权容易分析的的情况下,标准的 shared_ptr 和 weak_ptr 的组合总是有着比 gc_ptr 更好的性能,也因为实现简单,实现本身更不容易出现 BUG,特别是线程安全方面的问题;

对于所有权难分析,有着大量循环引用的图结构,自行实现一个局部的 Tracing GC,或者干脆在对象池里分配,最后连着对象池一起回收,这样实现无需负担引用计数的开销,性能要好的多;

对于一些要快糙狠做出实现,不追求性能的情况下,用户可能更倾向于用 Golang、Java 等语言,而非 C++。

我也提不出更多的建议了,不过我觉得题主应该再多考虑一下你这个 gc_ptr 的定位,再向这个方向优化, 或许就能找到一个能够大展身手的领域。