中对标记删除算法的介绍更多还是偏理论性质的。实践中,为了更好地满足现实的场景及需求,还需要对算法进行大量的调整。举个简单的例子,我们来看下JVM需要记录哪些信息才能让我们得以安全地分配对象空间。
碎片及整理(Fragmenting and Compacting)
JVM在清除不可达对象之后,还得确保它们所在的空间是可以进行复用的。对象删除会导致碎片的出现,这有点类似于磁盘碎片,这会带来两个问题:
- 写操作会变得更加费时,因为查找下一个可用空闲块已不再是一个简单操作。
- JVM在创建新对象的,会在连续的区块中分配内存。因此如果碎片已经严重到没有一个空闲块能足够容纳新创建的对象时,内存分配便会报错。
为了避免此类情形,JVM需要确保碎片化在可控范围内。因此,在垃圾回收的过程中,除了进行标记和删除外,还有一个“内存去碎片化”的过程。在这个过程当中,会给可达对象重新分配空间,让它们互相紧挨着对方,这样便可以去除碎片。下图展示的便是这一过程:
分代假设
如前所述,垃圾回收需要完全中止应用运行。显然,对象越多,回收的时间也越长。那么我们能不能在更小的内存区域上进行回收呢?通过可行性调查,一组研究人员发现应用中绝大多数的内存分配会分为两大类:
- 绝大部分的对象很快会变为不可用状态。
- 还有一些,它们的存活时间通常也不会很长。
这些结论最终构成了弱分代假设(Weak Generational Hypothesis)。基于这一假设,虚拟机内的内存被分为两类,新生代(Young Generation)及老生代(Old Generation)。后者又被称为年老代(Tenured Generation)。