对Mark and Sweep垃圾收集的介绍是最理论的知识点. 在实际中, 需要做许多调整来适应真实世界的场景和需求. 一个简单的例子, 我们来看看JVM需要做什么样的记录才能继续安全地分配对象。
2.1 分割和压缩(Fragmenting and Compacting)
无论何时发生了清除, JVM必须确保不可达对象占用的区域可以被重复使用. 这会(并且终将)产生内存碎片, 类似于磁盘碎片, 导致以下2个问题:
- 写操作变得更耗时因为找到下一块足够大的空闲内存变得越来越难
- 当创建新对象时, JVM会分配连续的内存块. 所以如果碎片多到没有单独的空闲碎片区域是足够大来容纳新创建的对象时, 会发生分配错误.
为了避免这样的问题, JVM要确保碎片不会脱离掌控. 所以取代仅仅标记和清除的, 是一个"内存碎片整理"过程也会发生在垃圾收集期间. 该过程重新分配所有可到达的对象靠近彼此, 消除(或减少)碎片. 示例如下:
gchandbook_减少碎片.png
2.2 分代假设
如之前提到的, 做垃圾收集会完全停掉应用. 很明显, 对象越多, 垃圾收集时间越长. 但是如果我们可以让它工作在小一点的内存空间呢? 为调查该可能性, 一组研究者观察到在应用中的大部分的内存分配有2种类别:
- 大部分对象迅速变为不可用
- 大部分对象通常不会存活很(非常)长时间
这些观察组成了 Weak Generational Hypothesis. 基于该假设, VM的内存被分为年轻代(Young Generation)和年老代(Old Generation). 后者有时候被称作Tenured.
网友评论