JVM 堆內存模型與 GC 策略

Java 中堆內存是 JVM 管理內存中最大的一塊內存,同時又是 GC 管理的重要區域。

Java 堆內存主要分成兩個區域:

1,年輕代。年輕代內部又分成了兩個區,一個是 Eden 區,一個是 Survivor 區。Survivor 區又劃分成兩塊,一塊是 from 區,一塊是 to 區;

2,老年代。

具體一點可以看圖:

一、年輕代

IBM 公司的專業研究表明,有將近 98% 的對象是朝生夕死,所以針對這一現狀大多數情況下,對象會在新生代 Eden 中進行分配,當 Eden 區沒有足夠空間的時候,虛擬機會觸發 Minor GC。

Minor GC 的回收速度很快。通過 Minor GC 後,Eden 區會被清空。Eden 區的絕大部分對象在這個時候都會被回收,剩下的那些無需被回收的對象會被放到 Survivor 的 from 區,如果 from 區放不下就直接會被放到 Old 區。

等到再次觸發 Minor GC 後會將 Eden 區和 from 區存活的對象放到 to 區。同樣的,如果 To 區放不下就會往 Old 區裏放。等到再下次觸發 Minor GC 後會將 Eden 區和 to 區存活的對象放到 From 區。Minor GC 會將年輕代的存活的數據在 from 區和 to 區來回存放。

在 Survivor 區中的存活數據,每經歷一次 Minor GC ,這些對象的年齡就會加 1,當長期存活的對象年齡達到 15 歲的時候就會被移到老年代。當然這個 15 ,JVM 支持特殊設置。

另外還有一個機制,虛擬機並不一定要對象年齡到達 15 歲纔會放入老年代,如果 Survivor 空間中相同年齡對象的大小的和大於 Survivor 空間的一半,年齡大約等於該年齡的對象就可以直接進入老年區,無需等待“成年”,這點類似於負載均衡。

二、老年代

老年代佔據着 2/3 的堆內存空間,只有在 Major GC 的時候纔會清理,每次 Major GC 都會觸發 “Stop-The-World”。內存越大,STW 的時間就越長,所以內存也不是越大越好。

除了年輕代那裏的數據會進入老年代之外,還有一種特殊情況:大對象。大對象是指大量連續內存空間的對象,這部分對象不管其生命週期有多短,都會直接進入老年代。這樣做的目的是爲了避免在 Eden 區和兩個 Survivor 區之間發生大量的內存複製。所以一定要注意這些大對象。

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