新生代使用Scavenge算法进行回收。在Scavenge算法的实现中,主要采用了Cheney算法。Cheney算法算法是一种采用复制的方式实现的垃圾回收算法。它将内存一分为二,每一部分空间称为semispace。在这两个semispace中,一个处于使用状态,另一个处于闲置状态。处于使用状态的semispace空间称为From空间,处于闲置状态的空间称为To空间,当我们分配对象时,先是在From空间中进行分配。当开始进行垃圾回收算法时,会检查From空间中的存活对象,这些存活对象将会被复制到To空间中(复制完成后会进行紧缩),而非活跃对象占用的空间将会被释放。完成复制后,From空间和To空间的角色发生对换。也就是说,在垃圾回收的过程中,就是通过将存活对象在两个semispace之间进行复制。可以很容易看出来,使用Cheney算法时,总有一半的内存是空的。但是由于新生代很小,所以浪费的内存空间并不大。而且由于新生代中的对象绝大部分都是非活跃对象,需要复制的活跃对象比例很小,所以其时间效率十分理想。复制的过程采用的是BFS(广度优先遍历)的思想,从根对象出发,广度优先遍历所有能到达的对象具体的执行过程大致是这样:首先将From空间中所有能从根对象到达的对象复制到To区,然后维护两个To区的指针scanPtr和allocationPtr,分别指向即将扫描的活跃对象和即将为新对象分配内存的地方,开始循环。循环的每一轮会查找当前scanPtr所指向的对象,确定对象内部的每个指针指向哪里。如果指向老生代我们就不必考虑它了。如果指向From区,我们就需要把这个所指向的对象从From区复制到To区,具体复制的位置就是allocationPtr所指向的位置。复制完成后将scanPtr所指对象内的指针修改为新复制对象存放的地址,并移动allocationPtr。如果一个对象内部的所有指针都被处理完,scanPtr就会向前移动,进入下一个循环。若scanPtr和allocationPtr相遇,则说明所有的对象都已被复制完,From区剩下的都可以被视为垃圾,可以进行清理了举个栗子(以及凑篇幅),如果有类似如下的引用情况:+----- A对象|根对象----+----- B对象 ------ E对象|+----- C对象 ----+---- F对象| +---- G对象 ----- H对象D对象在执行Scavenge之前,From区长这幅模样+---+---+---+---+---+---+---+---+--------+| A | B | C | D | E | F | G | H ||+---+---+---+---+---+---+---+---+--------+那么首先将根对象能到达的ABC对象复制到To区,于是乎To区就变成了这个样子:allocationPtr ↓ +---+---+---+----------------------------+| A | B | C ||+---+---+---+----------------------------+ ↑scanPtr接下来进入循环,扫描scanPtr所指的A对象,发现其没有指针,于是乎scanPtr移动,变成如下这样allocationPtr ↓ +---+---+---+----------------------------+| A | B | C ||+---+---+---+----------------------------+ ↑scanPtr接下来扫描B对象,发现其有指向E对象的指针,且E对象在From区,那么我们需要将E对象复制到allocationPtr所指的地方并移动allocationPtr指针:allocationPtr ↓ +---+---+---+---+------------------------+| A | B | C | E ||+---+---+---+---+------------------------+ ↑scanPtrB对象里所有指针都已被复制完,所以移动scanPtr:allocationPtr ↓ +---+---+---+---+------------------------+| A | B | C | E ||+---+---+---+---+------------------------+ ↑scanPtr接下来扫描C对象,C对象中有两个指针,分别指向F对象和G对象,且都在From区,先复制F对象到To区:allocationPtr ↓ +---+---+---+---+---+--------------------+| A | B | C | E | F ||+---+---+---+---+---+--------------------+ ↑scanPtr然后复制G对象到To区allocationPtr ↓ +---+---+---+---+---+---+----------------+| A | B | C | E | F | G ||+---+---+---+---+---+---+----------------+ ↑scanPtr这样C对象内部的指针已经复制完成了,移动scanPtr:allocationPtr ↓ +---+---+---+---+---+---+----------------+| A | B | C | E | F | G ||+---+---+---+---+---+---+----------------+ ↑scanPtr逐个扫描E,F对象,发现其中都没有指针,移动scanPtr:allocationPtr ↓ +---+---+---+---+---+---+----------------+| A | B | C | E | F | G ||+---+---+---+---+---+---+----------------+ ↑scanPtr扫描G对象,发现其中有一个指向H对象的指针,且H对象在From区,复制H对象到To区,并移动allocationPtr:allocationPtr ↓ +---+---+---+---+---+---+---+------------+| A | B | C | E | F | G | H ||+---+---+---+---+---+---+---+------------+ ↑scanPtr完成后由于G对象没有其他指针,且H对象没有指针移动scanPtr:allocationPtr ↓ +---+---+---+---+---+---+---+------------+| A | B | C | E | F | G | H ||+---+---+---+---+---+---+---+------------+ ↑ scanPtr此时scanPtr和allocationPtr重合,说明复制结束可以对比一下From区和To区在复制完成后的结果://From区+---+---+---+---+---+---+---+---+--------+| A | B | C | D | E | F | G | H ||+---+---+---+---+---+---+---+---+--------+//To区+---+---+---+---+---+---+---+------------+| A | B | C | E | F | G | H ||+---+---+---+---+---+---+---+------------+D对象没有被复制,它将被作为垃圾进行回收