JVM 垃圾回收和分页内存体系结构

2022-09-02 13:21:19

在最近10年讨论java和/或垃圾回收时,我无法辩护的唯一性能损失是垃圾回收算法在分页内存架构中运行时或多或少地中断,并且堆的一部分被分页。

Unix系统(尤其是Linux)会攻击性地分页出一段时间没有被触及的内存,虽然这对普通的泄漏c应用程序有好处,但它在内存紧张的情况下会扼杀java的性能。

我知道最佳做法是使最大堆小于物理内存。(或者你会看到你的应用程序交换到死)但是这个想法 - 至少在unix世界中,是内存可以更好地用于文件系统缓存等。

我的问题是:是否有任何分页(感知)垃圾回收算法?


答案 1

我要争辩说,这并不像你想象的那么大。

为了确保我们描述的是同样的事情:一个完整的集合需要JVM遍历对象图来识别每个可访问的对象;剩下的是垃圾。在这样做时,它将触及应用程序堆中的每个页面,如果已换出,这将导致每个页面都错误地进入内存。

我认为这不是一个值得关注的问题,原因有几个:首先,因为现代JVM使用代际收藏家,而且大多数物品从未从年轻一代中走出来,这些年轻一代几乎可以保证在居民集中。

其次,因为从年轻一代中移出的物品仍然倾向于经常被访问,这再次意味着它们应该在居民集中。这是一个更脆弱的论点,事实上,在很多情况下,除了GC之外,长期存在的对象不会被触及(我不相信内存有限的缓存的一个原因)。

第三个原因(可能还有更多)是因为JVM(至少是Sun JVM)使用标记扫描紧凑收集器。因此,在GC之后,堆中的活动对象占用的页面数量较少,再次增加了RSS。顺便说一句,这是 Swing 应用程序在最小化时显式调用 System.gc() 的主要驱动因素:通过压缩堆,当它们再次最大化时,可以交换的内容更少。


另外,要认识到 C/C++ 对象的堆碎片可能会变得极端,并且年轻的对象将散布在较旧的对象中,因此 RSS 必须更大。


答案 2

你是对的,垃圾回收器和虚拟内存管理器必须协作,否则GC将丢弃系统。Matthew Hertz、Yi Feng 和 Emery D. Berger 已经研究了这种 GC/内核协作。为了获得良好的性能,他们必须稍微扩展内核并调整垃圾回收器。

在高内存压力下,他们的基准测试使用GenMS Java GC需要大约160倍的时间。使用新的页面感知GC,基准测试仅慢了1.6倍。换句话说,使用正确调整的GC,可以获得100倍的性能提升。

http://lambda-the-ultimate.org/node/2391