分代垃圾回收,基于的是“大部分的對(duì)象,在生成后馬上就會(huì)變成垃圾”這一經(jīng)驗(yàn)上的事實(shí)為設(shè)計(jì)出發(fā)點(diǎn)。此前討論過基于引事實(shí)的另一個(gè)垃圾回收算法,引用計(jì)數(shù)出的一些優(yōu)化思路。
分代的關(guān)鍵是:
給對(duì)象記錄下一個(gè)age,隨著每一次垃圾回收,這個(gè)age會(huì)增加;
給不同age的對(duì)象分配不同的堆內(nèi)內(nèi)存空間,稱為某一代;
對(duì)某一代的空間,有適合其的垃圾回收算法;
對(duì)每代進(jìn)行不同垃圾回收,一般會(huì)需要一個(gè)額外的信息:即每代中對(duì)象被其他代中對(duì)象引用的信息。這個(gè)引用信息對(duì)于當(dāng)前代來說,扮演與"root"一樣的角色,也是本代垃圾回收的起點(diǎn)。
分代垃圾回收的典型是Ungar的分代垃圾回收。
它將堆分成如下形式:
如上,分成新生代與老年代。
在新生代內(nèi),又分成了生成空間與幸存空間。當(dāng)生成空間滿了,會(huì)以復(fù)制算法進(jìn)行垃圾回收,復(fù)制到幸存空間中。和前面的復(fù)制算法匹配,幸存空間又一分為二,分成from和to空間。每次新生代的垃圾回收,會(huì)同時(shí)進(jìn)行生成空間到to、from空間到to的兩個(gè)垃圾回收。
對(duì)于老年代,則直接進(jìn)行mark_sweep回收。
對(duì)于“記錄集”(record set),是記錄代間引用的一個(gè)數(shù)組。它內(nèi)部不能只記錄被引用對(duì)象,因?yàn)楸灰脤?duì)象被復(fù)制到to空間后,引用者本身的引用指針要更新,只記錄被引用的新生代內(nèi)對(duì)象是無法找到被引用者的。所以,必須在記錄集中記錄老年代內(nèi)對(duì)象。
更新記錄集的操作在分配新對(duì)象,并設(shè)置成老對(duì)象的一個(gè)field時(shí)進(jìn)行:
write_barrier(obj, field, new_obj) { if obj >= $old_start && new_obj < $old_start && obj.remembered == false // 條件,很明顯 $rs[$rs_idx++] = obj // 更新記錄集