[讨论] GC的历史综述与最新进展以及在HotSpot中的具体实现

RednaxelaFX 2014-11-01
HotSpot除了CMS和G1之外的GC所用的write barrier的思路源自Urs Hölzle的论文: A Fast Write Barrier for Generational Garbage Collectors。除了card size不同之外,实现细节跟当时在Self VM上用的一模一样。

HotSpot确实用的是512-byte cards, 1 byte per card来做card marking。Card marking是一种非准确式的记录跨代指针的办法——只要某个card所覆盖的GC堆区域存在跨代指针,该card就会被标记为非0(dirty)。然后minor GC的时候,所有dirty的card所覆盖的GC堆区域都会被当作root set的一部分来扫描。

用1 byte而不是1 bit来记录card是为了快。现代硬件都是最小按字节寻址的,没有直接存一个bit的指令,所以要用bit的话就不得不多用几条shift+mask指令,而用byte的指令数量可以少一些。当然在近几年的机器上其实又可以有新的取舍…毕竟原本的取舍来自20多年前了。

与之相对的是exact marking,就是每个标记精确到1个指针的粒度。取舍就正好相反。
ZHH2009 2014-11-01
多谢RednaxelaFX的解释,回复中提到的论文之前没看过,
不过在其他书或论文中有学习过card table和read/write barrier。

直到最近1周才有空深入的研究HotSpot GC代码,
然后常常有这么一个感觉:
就算从书上或论文中知道某个概念或算法了,
但是把它们对应到HotSpot中的哪些代码,这个过程还真不是件容易的事。

说回主题,非exact marking按我的理解在空间上浪费了一点,
虽节省了shift+mask指令,但是因为存在card iterate(虽然可以并行),
所以指令性能优势是否也抵消掉了。

《龙书》的7.7.2小节总结了write barrier的一些实现方式,
就是一个粒度的问题,是记录被写字段所在的对象,还是块,还是更大的Page,
我起初把HotSpot的方式理解成记录字段了,然后才转到512字节的块。

《龙书》中提到的第一种write barrier就是exact marking,精确到每个引用(字段),
第2种就是非exact的,然后粒度从对象到块到page。
作者也直说第2种更有效,不过我是不太理解为什么更有效。

粒度小点理论上能加快重新扫描的速度,
使用exact marking,因为实际中跨分代引用这个量的经验值不会太大吧,
先分配一段小空间,改了什么就精确记下什么,不够再加空间,
而不像HotSpot这样按堆大小来算卡表大小。

cardTableModRefBS.hpp中,又有段注释
引用

For object arrays, however, the barrier *is* precise;
ZHH2009 2014-11-01
Azul Systems公司在GC领域的论文:

2005年: 【The Pauseless GC Algorithm】
http://static.usenix.org/events/vee05/full_papers/p46-click.pdf

2011年: 【C4: The Continuously Concurrent Compacting Collector】
http://www.azulsystems.com/sites/default/files/images/c4_paper_acm.pdf
【C4的技术白皮书】
http://www.azulsystems.com/sites/default/files//images/wp_pgc_zing_v5.pdf

2012年: 【The Collie: A Wait-Free Compacting Collector】
http://www.lirmm.fr/~ducour/Doc-objets/ECOOP2012/ISMM/ismm/p85.pdf
RednaxelaFX 2014-11-14
我想提醒一下有些资料是会过时的。例如说:
Azul Systems To Open Source Significant Technology in Managed Runtime Initiative, InfoQ, 2010-06-16
Gil Tene 写道
Vega processors included a custom read barrier instruction that included bit field checking in reference metadata as well as special virtual memory protection for GC-compacted pages. Our x86-based JVM performs the semantic equivalent of Vega's read barrier operation using multiple x86 instructions, which in conjunction with using the x86 virtual memory subsystem to remap and protect GC-compacted pages achieve the same read barrier effect, and maintain the same algorithmic invariants needed for the Pauseless GC algorithms to work.

标红的部分当时的Zing在x86上确实是那么做的,但Azul早就已经转换到用别的方式来实现read barrier了,不再使用memory protect来实现这部分。实际实现很简单很直观呵呵~
LeafInWind 2014-11-26
有哪位大大能详细介绍一下G1算法的原理吗,看了“Garbage-First Garbage Collection”这篇论文,但感觉还是没有搞懂,比如2.2节开头说每个region都对应一个remembered set(以下简称rs),该rs记录所有可能包含指向当前region的指针的位置(which indicates all locations that might contain pointers to (live) objects within the region),但从下文看我怎么觉得rs中记录的应该是那些包含inter-region的指针的位置呢。另外每个collector线程都有一个rm log,它和region的rs是什么关系。然后又还有全局的filled RS buffers,等等等等,真的感觉有些乱了。而且论文中作者配的两个介绍原理的图实在太潦草了,完全没有说清楚。
不知哪位大大搞懂了,能详细解释一下整个算法过程,谢谢。
liberD 2015-03-13
RednaxelaFX 写道
ZHH2009 写道
另外,感觉Oracle/Sun在G1这一块的开发进度好慢啊,花了10年才做成这样,
这么慢的原因是什么?


有几个因素影响了Oracle/Sun对G1 GC的开发:
1、G1在JDK6时代产品化,从Sun Labs转交给产品组整合进HotSpot的主线代码里。这个时期正值Sun衰败,产品目标不明确而且人手严重不足。基本上就2-3个开发在做GC的工作,而且一部分精力还放到维护和调优现有的其它几个收集器上,使G1成熟得非常缓慢。
2、G1在JDK7、8时代推向一般开发者使用。Oracle收购了Sun之后,对Java的研发投入明显比Sun的末期要大,但HotSpot VM的研发人手不足情况仍然存在。GC方面,许多人力都被投入到NoPermGen项目和Java Flight Recorder项目中;而且Oracle的收购带来了一定程度的人员流失,例如G1的主力开发Tony Printezis就选择了离开Oracle,目前在Twitter研发G1。这样,这段时间在Oracle基本上只有一个有效的人头是在开发G1。
3、JDK9时代Oracle终于可以缓过劲来深入的打磨G1了。这就是我们看到的现状。


JDK9才开始打磨G1。那么,JDK7中的G1稳定性,可用性怎么样?是否建议在生产环境中使用JDK7中的G1?
RednaxelaFX 2015-03-14
liberD 写道
JDK9才开始打磨G1。那么,JDK7中的G1稳定性,可用性怎么样?是否建议在生产环境中使用JDK7中的G1?

JDK7u40之后的G1还挺稳定的。可以用用看。
是否适合在生产环境使用要看你们具体环境上测试的结果;G1的性能不一定比CMS好,要看具体情况。所以请自己测试对比看看。
Global site tag (gtag.js) - Google Analytics