爲什麼新生代內存需要有兩個Survivor區?

對於常見的GC算法,我們都應該知道,例如:標記清除算法、複製算法、標記整理算法等。標記清除算法由於回收之後存在大量的內存碎片,存在效率和空間問題!爲了解決效率問題,引出了複製算法!熟悉GC算法的小夥伴應該都看過周志明老師的《深入理解Java虛擬機》這本書。因此,這裏不再討論這幾種GC算法的區別,這裏假設大家都已經有所瞭解,爲了照顧遺忘的小夥伴,這裏祭出周志明老師的部分文章內容,沒有了解的趕緊下來補習一下!以下來自該書的截圖:(注:這裏只做交流學習使用!如需閱讀請購買正版!)

爲什麼新生代內存需要有兩個Survivor區?

 

爲什麼新生代內存需要有兩個Survivor區?

 

爲什麼新生代內存需要有兩個Survivor區?

 

那麼問題來了,在JVM的新生代內存中,爲什麼除了Eden區,還要設置兩個Survivor區?這是本篇文章探討的主要內容,我們一步一步的來分析!

一、爲什麼要有Survivor區

先不去想爲什麼有兩個Survivor區,第一個問題是,設置Survivor區的意義在哪裏?

爲什麼新生代內存需要有兩個Survivor區?

 

如果沒有Survivor,Eden區每進行一次Minor GC,存活的對象就會被送到老年代。老年代很快被填滿,觸發Major GC(因爲Major GC一般伴隨着Minor GC,也可以看做觸發了Full GC)。老年代的內存空間遠大於新生代,進行一次Full GC消耗的時間比Minor GC長得多。你也許會問,執行時間長有什麼壞處?頻發的Full GC消耗的時間是非常可觀的,這一點會影響大型程序的執行和響應速度,更不要說某些連接會因爲超時發生連接錯誤了。

好,那我們來想想在沒有Survivor的情況下,有沒有什麼解決辦法,可以避免上述情況:

爲什麼新生代內存需要有兩個Survivor區?

 

顯而易見,沒有Survivor的話,上述兩種解決方案都不能從根本上解決問題。

我們可以得到第一條結論:Survivor的存在意義,就是減少被送到老年代的對象,進而減少Full GC的發生,Survivor的預篩選保證,只有經歷16次Minor GC還能在新生代中存活的對象,纔會被送到老年代。

二、爲什麼要設置兩個Survivor區

設置兩個Survivor區最大的好處就是解決了碎片化,下面我們來分析一下。

爲什麼一個Survivor區不行?第一部分中,我們知道了必須設置Survivor區。假設現在只有一個survivor區,我們來模擬一下流程: 
剛剛新建的對象在Eden中,一旦Eden滿了,觸發一次Minor GC,Eden中的存活對象就會被移動到Survivor區。這樣繼續循環下去,下一次Eden滿了的時候,問題來了,此時進行Minor GC,Eden和Survivor各有一些存活對象,如果此時把Eden區的存活對象硬放到Survivor區,很明顯這兩部分對象所佔有的內存是不連續的,也就導致了內存碎片化。 
我繪製了一幅圖來表明這個過程。其中色塊代表對象,白色框分別代表Eden區(大)和Survivor區(小)。Eden區理所當然大一些,否則新建對象很快就導致Eden區滿,進而觸發Minor GC,有悖於初衷。

爲什麼新生代內存需要有兩個Survivor區?

 

碎片化帶來的風險是極大的,嚴重影響Java程序的性能。堆空間被散佈的對象佔據不連續的內存,最直接的結果就是,堆中沒有足夠大的連續內存空間,接下去如果程序需要給一個內存需求很大的對象分配內存。。。畫面太美不敢看。。。這就好比我們爬山的時候,揹包裏所有東西緊挨着放,最後就可能省出一塊完整的空間放相機。如果每件行李之間隔一點空隙亂放,很可能最後就要一路把相機掛在脖子上了。

那麼,順理成章的,應該建立兩塊Survivor區,剛剛新建的對象在Eden中,經歷一次Minor GC,Eden中的存活對象就會被移動到第一塊survivor space S0,Eden被清空;等Eden區再滿了,就再觸發一次Minor GC,Eden和S0中的存活對象又會被複制送入第二塊survivor space S1(這個過程非常重要,因爲這種複製算法保證了S1中來自S0和Eden兩部分的存活對象佔用連續的內存空間,避免了碎片化的發生)。S0和Eden被清空,然後下一輪S0與S1交換角色,如此循環往復。如果對象的複製次數達到16次,該對象就會被送到老年代中。下圖中每部分的意義和上一張圖一樣,就不加註釋了。

爲什麼新生代內存需要有兩個Survivor區?

 

上述機制最大的好處就是,整個過程中,永遠有一個survivor space是空的,另一個非空的survivor space無碎片。

那麼,Survivor爲什麼不分更多塊呢?比方說分成三個、四個、五個?顯然,如果Survivor區再細分下去,每一塊的空間就會比較小,很容易導致Survivor區滿,因此,我認爲兩塊Survivor區是經過權衡之後的最佳方案。

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