復(fù)制垃圾回收算法(Copying GC),是1963年由Marvin L. Minsky 研究得出的垃圾回收算法秘车,簡單的說它是通過將內(nèi)存分為兩個空間蚌卤,在垃圾回收是將空間1的活動對象末早,直接復(fù)制到空間2中啊片,然后全部回收掉空間1的對象。這里的空間1和空間2刘绣,分別被稱為來源空間和目標(biāo)空間樱溉。
碰撞分配
碰撞分配算法是在復(fù)制GC中,通過碰撞或者遞增指針來跟蹤下次分配發(fā)生的地方纬凤,以便從大塊連續(xù)的內(nèi)存堆中分配相鄰的內(nèi)存段福贞。下圖就是復(fù)制GC持有的分配指針,在每次內(nèi)存分配的時候停士,它從內(nèi)存堆中返回一段內(nèi)存地址挖帘,然后再將分配指針向后移動,這樣地址空間時連續(xù)的恋技,但是因為分配的對象大小的不同拇舀,所以分配的比例并不是平均的。
這種方式的優(yōu)點是蜻底,簡單易行骄崩,運行速度快,并且因為每次分配的內(nèi)存段都是相鄰的,所以具有很好的局部引用性要拂,意思就是應(yīng)用程序如果重復(fù)訪問同一片內(nèi)存段抠璃,那么CPU可以將那片內(nèi)存段緩存起來,用以提供程序訪問的速度脱惰。
半空間算法
碰撞分配講到了復(fù)制GC如何分配鸡典,半空間算法才是真正的垃圾回收,半空間算法是在枪芒,初始內(nèi)存堆消耗殆盡時,通過GC標(biāo)識存活對象和垃圾對象(這個階段和標(biāo)記清除算法是一樣的)也就是標(biāo)記階段谁尸,在回收階段舅踪,GC將通過碰撞分配的來源空間(From-Space)中的存活的對象,全部移動到目標(biāo)空間(To-Space)中良蛮。
上圖中"M"的區(qū)域就是存活的對象抽碌,空白區(qū)域是垃圾對象底部空間就是目標(biāo)空間(To-Space)在回收階段復(fù)制GC將存活對象連續(xù)的復(fù)制到目標(biāo)空間(進(jìn)行保持局部引用性)分配指針向后移動。
我們從上圖看到存活對象已經(jīng)被全部復(fù)制到目標(biāo)空間决瞳,但是我們的內(nèi)存分配只能在來源空間進(jìn)行货徙,并且現(xiàn)在來源空間的內(nèi)存還沒有被回收掉,那么復(fù)制GC的最后一個階段就是空間交換皮胡,然后在交換完成是清空目標(biāo)空間痴颊。
半空間算法的簡單快速的優(yōu)點,同時帶來了另外一個問題屡贺,就是內(nèi)存使用的低效蠢棱,我們需要維護(hù)兩個空間相同的內(nèi)存堆來,并且僅僅有一個內(nèi)存對是當(dāng)前能夠正在被使用的甩栈,意味著要分配實際使用內(nèi)存的兩倍泻仙。
總結(jié)
我們來回顧一下復(fù)制垃圾回收算法的優(yōu)缺點
優(yōu)點
- 高吞度量:因為僅僅需要在標(biāo)記階段消耗實際,復(fù)制階段無需太多時間量没,所以GC的時間消耗和空間中的活動對象數(shù)量成正比玉转,相比于標(biāo)記清除GC有較高的吞吐量。
- 高速分配:與標(biāo)記清除算法使用空閑列表進(jìn)行內(nèi)存分配不同殴蹄,復(fù)制GC使用連續(xù)的內(nèi)存空間究抓,這樣就省去的使用空閑列表,分配內(nèi)存時袭灯,線性查找可分配空間的時間消耗漩蟆。
- 局部引用緩存和空間壓縮:因為復(fù)制GC的分配是連續(xù)的,所以在可以利用局部引用緩存妓蛮,并且每次GC后內(nèi)存空間都會被集中到空間的一段怠李,也就實現(xiàn)了空間壓縮。
缺點
- 空間效率低 復(fù)制GC需使用兩個堆空間,也就是實際空間的兩倍捺癞,這樣的內(nèi)存消耗耗是比較客觀的夷蚊。
- 遞歸復(fù)制 因要整體的復(fù)制存活對象到目標(biāo)空間去,所以復(fù)制GC使用了遞歸方式髓介,復(fù)制存活對象的子對象惕鼓。如果遞歸層次太深還可能產(chǎn)生溢出。