在JVM中,內存是按照分代進行組織的。算法
其中,堆內存分爲年輕代和年老代,非堆內存主要是Permanent區域,主要用於存儲一些類的元數據,常量池等信息。而年輕代又分爲兩種,一種是Eden區域,另一種是兩個大小對等的Survivor區域。之因此將Java內存按照分代進行組織,主要是基於這樣一個「弱假設」 - 大多數對象都在年輕時候死亡。同時,將內存按照分代進行組織,使得咱們能夠在不一樣的分代上使用不一樣的垃圾回收算法,使得整個內存的垃圾回收更加有效。多線程
在年輕代上採用的垃圾回收算法是「Mark-Copy」算法,並不一樣於咱們前面所瞭解的任何一種基本垃圾回收算法,可是Mark算法是同樣的,基於根對象找到全部的可達對象,具體可看Mark-Sweep算法中的Mark步驟. 而對於Copy算法,它僅僅是簡單的將符合必定年齡的對象從一個分代拷貝到另外一個分代。具體的回收過程以下:線程
首先,新對象的內存分配都是先在Eden區域中進行的,當Eden區域的空間不足於分配新對象時,就會觸發年輕代上的垃圾回收(發生在Eden和Survivor內存區域上),咱們稱之爲"minor garbage collection".同時,每一個對象都有一個「年齡」,這個年齡實際上指的就是該對象經歷過的minor gc的次數。如圖1所示,當對象剛分配到Eden區域時,對象的年齡爲「0」,當minor gc被觸發後,全部存活的對象(仍然可達對象)會被拷貝到其中一個Survivor區域,同時年齡增加爲「1」。並清除整個Eden內存區域中的非可達對象。對象
當第二次minor gc被觸發時(如圖2所示),JVM會經過Mark算法找出全部在Eden內存區域和Survivor1內存區域存活的對象,並將他們拷貝到新的Survivor2內存區域(這也就是爲何須要兩個大小同樣的Survivor區域的緣由),同時對象的年齡加1. 最後,清除全部在Eden內存區域和Survivor1內存區域的非可達對象。內存
當對象的年齡足夠大(這個年齡能夠經過JVM參數進行指定,這裏假定是2),當minor gc再次發生時,它會從Survivor內存區域中升級到年老代中,如圖3所示。get
其實,即便對象的年齡不夠大,可是Survivor內存區域中沒有足夠的空間來容納從Eden升級過來的對象時,也會有部分對象直接升級到Tenured內存區域中。it
當minor gc發生時,又有對象從Survivor區域升級到Tenured區域,可是Tenured區域已經沒有空間容納新的對象了,那麼這個時候就會觸發年老代上的垃圾回收,咱們稱之爲"major garbage collection".io
而在年老代上選擇的垃圾回收算法則取決於JVM上採用的是什麼垃圾回收器。經過的垃圾回收器有兩種:Parallel Scavenge(PS) 和Concurrent Mark Sweep(CMS)。這兩種垃圾回收器的不一樣更多的是體如今年老代的垃圾回收過程當中,年輕代的垃圾回收過程在這兩種垃圾回收器中基本上是一致的。效率
就像其名字所表示的那樣,Parallel Scavenge垃圾回收器在執行垃圾回收時使用了多線程來一塊兒進行垃圾回收,這樣能夠提升垃圾回收的效率。而Concurrent Mark Sweep垃圾回收器在進行垃圾回收時,應用程序能夠同時運行。垃圾回收
PS垃圾回收器在年老代上採用的垃圾回收算法能夠看做是標記-清除算法和標記-壓縮算法的結合體。
首先,PS垃圾回收器先是會在年老代上使用標記-清除算法來回收掉非可達對象所佔有的空間,可是咱們知道,標記清除算法的一個缺陷就是它會引發內存碎片問題。繼而有可能會引起連續的major gc。假設當前存在的內存碎片有10M,但最大的內存碎片只能容納2M的對象,這個時候若是有一個3M的對象從Survivor區域升級到Tenured區域,那Tenured區域也沒有辦法存放這個3M的對象。結果就是不斷的觸發major gc,直到Out of Memory。因此,PS垃圾回收器在清除非可達對象後,還會進行一次compact,來消除內存碎片。
CMS垃圾收集器相比於PS垃圾收集器,它成功的減小了垃圾收集時暫停應用程序的時間,由於CMS在進行垃圾收集時,應用程序是能夠並行運行的。下面讓咱們來看看它是怎麼作到的。
從它的名字能夠看出,CMS垃圾收集器在年老代上採用的垃圾回收算法是標記-清除算法。可是,它跟標準的標記-清除算法略有不一樣。它主要分爲四個階段:
從下圖能夠看到PS和CMS垃圾收集器的區別:
黑色箭頭表明應用程序的運行,綠色箭頭表明CMS垃圾收集器的運行。一根線條表示單線程,多個線條表示多線程。
因此,相比於PS垃圾收集器,CMS垃圾收集器成功的減小了應用程序暫時的時間。
可是很不幸的是,CMS垃圾收集器雖然減小了暫停應用程序的運行時間,可是因爲它沒有Compact階段,它仍是存在着內存碎片問題。因而,爲了去除內存碎片問題,同時又保留CMS垃圾收集器低暫停時間的優勢,JAVA7發佈了一個新的垃圾收集器 - G1垃圾收集器。它會在將來逐步替換掉CMS垃圾收集器。
G1垃圾收集器和CMS垃圾收集器有幾點不一樣。首先,最大的不一樣是內存的組織方式變了。Eden,Survivor和Tenured等內存區域再也不是連續的了,而是變成了一個個大小同樣的region - 每一個region從1M到32M不等。
一個region有可能屬於Eden,Survivor或者Tenured內存區域。圖中的E表示該region屬於Eden內存區域,S表示屬於Survivor內存區域,T表示屬於Tenured內存區域。圖中空白的表示未使用的內存空間。G1垃圾收集器還增長了一種新的內存區域,叫作Humongous內存區域,如圖中的H塊。這種內存區域主要用於存儲大對象-即大小超過一個region大小的50%的對象。
在G1垃圾收集器中,年輕代的垃圾回收過程跟PS垃圾收集器和CMS垃圾收集器差很少,新對象的分配仍是在Eden region中,當全部Eden region的大小超過某個值時,觸發minor gc,回收Eden region和Survivor region上的非可達對象,同時升級存活的可達對象到對應的Survivor region和Tenured region上。對象從Survivor region升級到Tenured region依然是取決於對象的年齡。
對於年老代上的垃圾收集,G1垃圾收集器也分爲4個階段,基本跟CMS垃圾收集器同樣,但略有不一樣:
從上能夠看到,因爲Initial Mark階段和Clean up/Copy階段都是跟minor gc同時發生的,相比於CMS,G1暫停應用程序的時間更少,從而提升了垃圾回收的效率。
摘自:http://www.jianshu.com/p/778dd3848196