Java HotSpot VM(以下簡稱JVM)把Heap區劃分為不同世代區塊,是基於對物件生命週期(objects lifetimes)的世代假設(generational hypothesis)。
當物件不再被應用程式參照後,就是所謂的垃圾物件(garbage objects)。而最簡單的垃圾回收演算法就是遍歷(iterate)每一個物件並檢查是否有被參照,那些沒被參照的就是垃圾物件。此演算法花費的時間與物件數量呈正比,在有大量物件的大型應用程式以此簡單算法來處理垃圾回收耗費的時間太長,因此不適合用在大型應用程式。
因此JVM採用世代回收(generational collection)機制並搭配數種演算法來處理垃圾物件的回收。世代回收是根據觀察應用程式中物件的存活特性來回收垃圾物件,企圖減少回收工作的時間。而「物件的存活特性」就是指物件的世代假設(generational hypothesis),其論述為大部分物件的存活時間都很短。
下圖為典型的物件生命週期分布圖,X軸為物件存活時間,越右邊代表時間越長;Y軸代表物件的數量,越上面代表物件的數量越多。(我是覺得這張圖的X軸應該標註為Time(時間),而不是Bytes Allocates(分配的位元組))。
物件生命週期的典型分布狀況
在圖的左方有一個高峰代表那些生命很短的物件,通常是那些在迴圈中產生的物件,在迴圈結束後就不被使用等著被回收。而最右邊則是存活時間很長的物件,例如在整個應用程式執行結束前都持續被使用的物件。而有效的垃圾回收即是基於「大部分的物件生命都很短」的假設來設計。
這也就是為什麼JVM的Heap記憶體空間被規劃為多個世代區塊的原因,當某個世代區塊空間被垃圾物件填滿時,就會觸發屬於該世代區塊的垃圾回收。
因為大部分的物件在年輕世代(Young Generation)就會死去,所以年輕世代區塊很快會被填滿,並觸發Minor GC來回收年輕世代的記憶體空間,其他世代則不進行GC。又年輕世代的空間比較小,所以Minor GC的速度比較快,發生頻率比較高。
而當老年世代(Old Generation/Tenured generation)的空間被垃圾物件填滿時,會觸發Major GC來回收老年世代的記憶體空間,又老年世代的空間比較大,所以Major GC要耗費比較長的時間。
沒有留言:
張貼留言