經過了JVM區域的學習,我們知道在堆中新生代具有一個Eden區和兩個Survivor區,這裡就有疑問了,為什麼需要Survivor區和為什麼需要兩個Survivor區?帶著疑問我們思考一下。
一、為什麼需要Survivor區?
帶著這個問題,我們假設一下,如果沒有Survivor區,新生代只有Eden區。
當Eden區裝滿後,Minor GC進行垃圾回收,倖存的物件會直接放入老年代,可以想到,要不了多久老年代就會裝滿,便會進行Major GC且連帶Minor GC也就是Full GC,每次Full GC都會消耗大量的時間。也許你會問,執行時間長有什麼問題?頻發的Full GC會消耗大量的時間,會影響程式的執行與響應速度,導致連線超時等等一系列問題。所以,會出現老年代頻發Full GC而嚴重影響效率的問題。
那麼,如果不依靠Survivor區,我們應該如何解決老年代頻發Full GC的問題呢?
方案 | 優點 | 缺點 |
---|---|---|
增大老年代記憶體空間 | 更多物件才會填滿老年代,降低Full GC頻率 | 每次GC消耗更長的時間 |
減小老年代記憶體空間 | Full GC執行時間減少 | Full GC頻率增加 |
由此可見,沒有Survivor區無法從根本解決問題。
結論:Survivor具有預篩選保證,只有物件到一定歲數才會送往老年代,Survivor區可以減少被送到老年代的物件,進而減少Full GC發生。
二、為什麼需要兩個Survivor區?
可以知道,新生代使用複製回收演算法,我們設想一下只有一個Survivor區會發生什麼情況。
當Eden區填滿後,Minor GC進行垃圾回收,倖存的物件會移動到Survivor區,這樣迴圈往復。此時,Survivor區被裝滿了,也會進行Minor GC,將一些物件kill掉,倖存的物件只能儲存在原來的位置,這樣就會出現大量的記憶體碎片(被佔用記憶體不連續)。
記憶體碎片化是嚴重影響效能的,可以設想當有一個稍大一點的物件從Eden區存活轉入Survivor區,發現空閒記憶體斷斷續續,沒有他能落腳的地方,就只能直接存到老年代了,如此反覆,老年代會出現我們第一部分的問題。打個比方:我們出去郊遊,一些吃的罐頭,玩的玩具隨便放在包裡,最後發現最主要的摺疊帳篷放不進去了,只好手拿著到處溜達,非常不方便且影響心情。
最後,如果有兩個Survivor區,便可以保證一個為空,另一個是非空且無碎片儲存的。