瞭解JVM GC原理很是重要,對於系統調優很是有用。若是一個系統頻繁發生FULL GC,那麼會形成系統響應卡頓,更嚴重的時候會致使系統崩潰。安全
JVM的內存空間,從大的層面上來分析包含:新生代空間(Young)和老年代空間(Old)。新生代空間(Young)又被分爲2個部分(Eden區域、Survivous區域)和3個板塊(1個Eden區域和2個Survivous區域)spa
下邊來看下具體每部分都是用來幹什麼的。線程
1)Eden(伊甸園)區域:用來存放使用new或者newInstance等方式建立的對象,默認這些對象都是存放在Eden區,除非這個對象太大,或者超出了設定的閾值-XX:PretenureSizeThresold,這樣的對象會被直接分配到Old區域。3d
2)2個Survivous(倖存)區域:通常稱爲S0,S1,理論上他們同樣大。code
下邊將會講解它們如何工做的。對象
在不斷建立對象的過程當中,當Eden區域被佔滿,此時會開始作Young GC也叫Minor GCblog
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區域。get
3)將Eden區域空間清空,此時From Survivous區域(S1)也是空的。it
4)S0與S1互相切換標籤,S0爲From Survivous,S1爲To Survivous。
當第二次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 決定)。
從根引用開始,對象的內部屬性可能也是引用,只要能級聯到的都被認爲是活着的對象。
本地變量引用,操做數棧引用,PC寄存器,本地方法棧引用等這些都是根。
Old區域通常稱爲老年代,老年代與新生代不同。新生代,咱們能夠認爲存活下來的對象不多,而老年代則相反,存活下來的對象不少,因此JVM的堆內存,纔是咱們一般關注的主戰場,由於這裏面活着的對象很是多,因此發生一次FULL GC,來找出來全部存活的對象是很是耗時的,所以,咱們應該避免FULL GC的發生。
通常來講很小,咱們大概知道它與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%)。
默認是15次,參數設置
--XX:MaxTenuringThreshold=15
,計數器會在對象的頭部記錄它的交換次數。
在發生FULL GC的時候,意味着JVM會安全的暫停全部正在執行的線程(Stop The World),來回收內存空間,在這個時間內,全部除了回收垃圾的線程外,其餘有關JAVA的程序,代碼都會靜止,反映到系統上,就會出現系統響應大幅度變慢,卡機等狀態。
參考:《透視JVM之垃圾回收》