了解JVM GC原理非常重要,對於系統調優非常有用。如果一個系統頻繁發生FULL GC,那么會造成系統響應卡頓,更嚴重的時候會導致系統崩潰。
JVM的內存空間
JVM的內存空間,從大的層面上來分析包含:新生代空間(Young)和老年代空間(Old)。新生代空間(Young)又被分為2個部分(Eden區域、Survivous區域)和3個板塊(1個Eden區域和2個Survivous區域)
下邊來看下具體每部分都是用來干什么的。
1)Eden(伊甸園)區域:用來存放使用new或者newInstance等方式創建的對象,默認這些對象都是存放在Eden區,除非這個對象太大,或者超出了設定的閾值-XX:PretenureSizeThresold,這樣的對象會被直接分配到Old區域。
2)2個Survivous(幸存)區域:一般稱為S0,S1,理論上他們一樣大。
下邊將會講解它們如何工作的。
第一次GC:
在不斷創建對象的過程中,當Eden區域被占滿,此時會開始做Young GC也叫Minor GC
1)第一次GC時Survivous中S0區和S1區都為空,將其中一個作為To Survivous(用來存儲Eden區域執行GC后不能被回收的對象)。比如:將S0作為To Survivous,則S1為From Survivous。
2)將Eden區域經過GC不能被回收的對象存儲到To Survivous(S0)區域(此時Eden區域的內存會在垃圾回收的過程中全部釋放),但如果To Survivous(S0)被占滿了,Eden中剩下不能被回收對象只能存放到Old區域。
3)將Eden區域空間清空,此時From Survivous區域(S1)也是空的。
4)S0與S1互相切換標簽,S0為From Survivous,S1為To Survivous。
第二次GC:
當第二次Eden區域被占滿時,此時開始做GC
1)將Eden和From Survivous(S0)中經過GC未被回收的對象遷移到To Survivous(S1),如果To Survious(S1)區放不下,將剩下的不能回收對象放入Old區域;
2)將Eden區域空間和From Survivous(S0)區域空間清空;
3)S0與S1互相切換標簽,S0為To Survivous,S1為From Survivous。
第三次,第四次一次類推,始終保證S0和S1有一個空的,用來存儲臨時對象,用於交換空間的目的。反反復復多次沒有被淘汰的對象,將會被放入Old區域中,默認15次(由參數--XX:MaxTenuringThreshold=15 決定)。
GC中相關問題
問題1:怎么定義活着的對象?
從根引用開始,對象的內部屬性可能也是引用,只要能級聯到的都被認為是活着的對象。
問題2:什么是根?
本地變量引用,操作數棧引用,PC寄存器,本地方法棧引用等這些都是根。
問題3:對象進入Old區域有什么壞處?
Old區域一般稱為老年代,老年代與新生代不一樣。新生代,我們可以認為存活下來的對象很少,而老年代則相反,存活下來的對象很多,所以JVM的堆內存,才是我們通常關注的主戰場,因為這里面活着的對象非常多,所以發生一次FULL GC,來找出來所有存活的對象是非常耗時的,因此,我們應該避免FULL GC的發生。
問題4:S0和S1一般多大,靠什么參數來控制,有什么變化?
一般來說很小,我們大概知道它與Young差不多相差一倍的比例,設置的參數主要有兩個:
-XX:SurvivorRatio=8 -XX:InitialSurvivorRatio=8
第一個參數(-XX:SurvivorRatio)是Eden和Survivous區域比重(注意Survivous一般包含兩個區域S0和S1,這里是一個Survivous的大小)。如果將-XX:SurvivorRatio=8設置為8,則說明Eden區域是一個Survivous區的8倍,換句話說S0或S1空間是整個Young空間的1/10,剩余的8/10由Eden區域來使用。
第二個參數(-XX:InitialSurvivorRatio)是Young/S0的比值,當其設置為8時,表示S0或S1占整個Young空間的1/8(或12.5%)。
問題5:一個對象每次Minor GC時,活着的對象都會在S0和S1區域轉移,講過MInor GC多少次后,會進入Old區域呢?
默認是15次,參數設置
--XX:MaxTenuringThreshold=15
,計數器會在對象的頭部記錄它的交換次數。
問題6:為什么發生FULL GC會帶來很大的危害?
在發生FULL GC的時候,意味着JVM會安全的暫停所有正在執行的線程(Stop The World),來回收內存空間,在這個時間內,所有除了回收垃圾的線程外,其他有關JAVA的程序,代碼都會靜止,反映到系統上,就會出現系統響應大幅度變慢,卡機等狀態。
參考:《透視JVM之垃圾回收》