JVM堆內存結構分配

JVM的堆內存分爲新生代(Young Generation)和舊生代(Old Generation)。新生代分爲Eden區和Survivor區。Survivor區分爲From SurvivorTo Survivor。如圖:


從上圖可以看出,新生代通常佔JVM堆內存的1/3,因爲新生代存儲都是新創建的對象,比較小的對象,而老年代存的都是比較大的,活的久的對象,所以老年代佔JVM堆內存較大;還可以看出,新生代裏的Eden區通常佔年輕代的4/5,兩個Survivor分別佔新生代的1/10。因爲Survivor中存儲的是GC之後倖存的對象,實際上只有很少一部分會倖存,所以Survivor佔的比例比較小。

下面講解一下當對象A創建之後,對象A在各個區之間的流轉過程,也就是各個區作用。

1) 對象Anew出來之後,是被存放在Eden區的。註釋:Eden即伊甸園,亞當和夏娃的故事

2) 當發生一次GC之後,Eden區存活下來的對象A會被複制到Survivor 1區(此時Survivor 1To Survivor);Survivor 0 (此時爲From Survivor)中存活的對象也會被複制到Survivor 1中。

3) GC會清空EdenSurvivor 0 (即From Survivor)中存儲的所有對象。因爲EdenSurvivor 0 中存活的對象都被複制到 Survivor 1中了,所以清空是沒問題的。

4) 交換Survivor 0Survivor 1的角色:即此時有數據的Survivor 1作爲From Survivor,被清空的Survivor 0作爲To Survivor。要保證在GC發生之前,To Survivor永遠是空的那個

5) 下次GC發生時,重複上述步驟。將Eden中存活的對象複製到To Survivor,將From Survivor中活的對象也複製到To Survivor

說到此處,有細心的同學會發現,這都是新生代之間的作用,那老年代呢?

其實是這樣的,在上述步驟中,發生GC時,From Survivor中存活的對象並不是全部都會被複制到To Survivor中,而是根據這個對象在Survivor區中存活了多久而決定去向,當一個對象在Survivor中存活了很久(即經歷了多次GC還沒死),就會在發生GC時被複制到舊生代中。

一個很形象的例子描述對象在JVM堆內存中的生命週期:

我是一個普通的java對象,我出生在Eden區,在Eden區我還看到和我長的很像的小兄弟,我們在Eden區中玩了挺長時間。有一天Eden區中的人實在是太多了,我就被迫去了Survivor區的“To”區,自從去了Survivor區,我就開始漂泊了,因爲Survivor的兩個區總是交換名字,所以我總是搬家,搬到To Survivor居住,搬來搬去,居無定所。直到我18歲的時候,爸爸說我成人了,該去社會上闖闖了。於是我就去了年老代那邊,年老代裏,人很多,並且年齡都挺大的,我在這裏也認識了很多人。在年老代裏,我生活了20(每次GC加一歲),然後被回收。

 

還有要理解爲什麼對象在新生代中複製來複制去的,而不是將死的直接清除,老的直接複製到舊生代?

這樣做的好處就是減少了內存碎片,而直接清除的話會使內存很零碎。詳情可以瞭解一下java垃圾回收算法中的複製算法。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章