透視JVM之垃圾回收

 

JVM是JAVA世界的核心,瞭解它有助於我們更好調試,調優和開發程序,最近散仙在看JAVA特種兵一書,看完覺得,作者寫的內容還是挺不錯,大家感興趣的,也可以購買本溫故而知新下。 

在JVM中,我們經常提到的就是堆了,堆確實很重要,其實,除了堆之外,還有幾個重要的模塊,看下圖: 


 
大多數情況下,我們並不需要關心JVM的底層,但是如果瞭解它的話,對於我們系統調優是非常有用的,在這裏面瞭解JVM的GC原理,是非常重要的一塊知識。我們都知道對於一個大型網站,如果JVM頻繁發生FULL GC,那麼將會是致命的危險,不僅僅會造成網站響應遲鈍,更嚴重的時候會導致系統崩潰,這對用戶體驗來講,都是我們不願意看到的。 

在JVM裏的內存空間,從大的層面劃分,主要有新生代空間(Young)和老年代空間(Old),其中Young空間,又被分爲2個部分和3個板塊,分別是1個Egen區,和2個Survivor區,看下圖: 


 
OK,下面來具體看下,每部分都是幹啥的 
(1)Eden區域是用來存放使用new或者newInstance等方式創建的對象,默認都是存放在Eden區,除非這個對象太大,或者超過了設定的閾值-XX:PretenureSizeThresold,這樣的對象會被直接分配到Old區域。 

(2)2個Survivor(倖存)區,一般稱S0,S1,理論上他們是一樣大的,解釋一下,他們是如何工作的: 
在不斷創建對象的過程中,Eden區會滿,這時候會開始做Young G也叫Minor GC,而Young空間的第一次GC就是找出Eden區中,倖存活着的對象,然後將這些對象,放到S0,或S1區中的其中一個, 假設第一次選擇了S0,它會逐步將活着的對象拷貝到S0區域,但是如果S0區域滿了,剩下活着的對象只能放old區域了,接下來要做的是,將Eden區域清空,此時時候S1區域也是空的。 

當第二次Eden區域滿的時候,就將Eden區域中活着的對象+S0區域中活着的對象,遷移到S1中,如果S1放不下,就會將剩下的部門,放到Old區域中,只是這次對象來源區域增加了S0,最後會將Eden區+S0區域,清空 

第三次和第四次依次類推,始終保證S0和S1有一個是空的,用來存儲臨時對象,用於交換空間的目的,反反覆覆多次沒有被淘汰的對象,將會放入old區域中,默認是15次。具體的交換過程就和上圖中的信息相似。 




問題一:怎麼定義活着的對象? 
從根引用開始,對象的內部屬性可能也是引用,只要能級聯到的都被認爲是活着的對象 

問題二:什麼是根? 
本地變量引用,操作數棧引用,PC寄存器,本地方法棧引用等這些都是根。 

問題三:對象進入Old區域有什麼壞處? 
old區域一般稱爲老年代,老年代與新生代不一樣,年輕代,我們可以認爲存活下來的對象很少,而老年代則相反,存活下來的對象很多,所以JVM的堆內存,纔是我們通常關注的主戰場,因爲這裏面活着的對象非常多,所以發生一次FULL GC,來找出來所有存活的對象是非常耗時的,因此,我們應該儘量避免FULL GC的發生。 

問題四:S0和S1一般多大,靠什麼參數來控制,有什麼變化? 

一般來說很小,我們大概知道它與Young差不多相差一倍的比例,設置的的參數主要有兩個: 
-XX:SurvivorRatio=8 
-XX:InitialSurvivorRatio=8 

第一個參數是Eden和Survivor區域比重,注意是一個Survivor的的大小,如果將其設置爲8,則說明Eden區是一個Survivor區的8倍,換句話說S0或S1空間是整個Young空間的1/10,剩餘的80%由Eden區域來使用。 

第二個參數是Young/S0的比值,當其設置爲8時,表示s0或s1佔整個Young空間的12.5%。 


問題五;一個對象每次Minor Gc時,活着的對象都會在s0和s1區域轉移,經過經過Minor GC多少次後,會進入Old區域呢? 

默認是15次,參數設置-XX:MaxTenuringThreshold=15,計數器會在對象的頭部記錄它交換的次數 


問題六:爲什麼發生FULL GC會帶來很大的危害? 

在發生FULL GC的時候,意味着JVM會安全的暫停所有正在執行的線程(Stop The World),來回收內存空間,在這個時間段內,所有除了回收垃圾的線程外,其他有關JAVA的程序,代碼都會靜止,反映到系統上,就會出現系統響應大幅度變慢,卡機等狀態。 

舉個通俗易懂點的例子,就是在一個房間裏,如果有一個人,不停的扔垃圾,然後有一個清潔工不停掃垃圾,這時候,我們的系統是OK的,因爲基本不會出現垃圾堆滿房間的情景,而且因爲清潔工可以對付過來,假設現在有10個人不停扔垃圾,那麼就房間就會很快被堆滿,這時候清潔工,由於工作不過來了,大聲吼一聲,你們都暫停3分鐘,別再扔了,我先把這個房間打掃完,你們纔可以扔。 
在這個場景中,一個人扔,一個人掃,就類似於Minor GC,這時候,並不會影響扔垃圾的人,然後一旦10個人同時仍,而且很快就沒地方仍了,這時候,就會觸發Full GC,然後JVM下令,你們暫時都別仍了,等我什麼時候回收完垃圾了,你們在仍,現在大家清楚了吧,所謂的10個人,就是類似我們成千上百的java類,在不停的執行任務,所謂的清潔工,就是我們的GC機制,所以,大家在平時編碼的時候,一定注意儘量少造點垃圾對象,這樣觸發FULL GC的機率,纔會變小。 

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