1. 程式人生 > >為什麼新生代需要有兩個Survivor區

為什麼新生代需要有兩個Survivor區

轉載自:http://blog.csdn.net/antony9118/article/details/51425581

1.為什麼要有Survivor區

  首先思考設定Survivor區的意義在哪裡?
  如果沒有Survivor,Eden區每進行一次Minor GC,存活的物件就會被送到老年代。老年代很快被填滿,觸發Major GC(也可以看做觸發了Full GC)。老年代的記憶體空間遠大於新生代,進行一次Full GC消耗的時間比Minor GC長得多。頻發的Full GC消耗的時間是非常多的,這一點會影響大型程式的執行和響應速度。

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

  1. 增加老年代空間
    使更多的存活物件才能填滿老年代,降低Full GC頻率,但隨著老年代空間加大,一旦發生Full GC,執行所需要的時間更長。
  2. 減少老年代空間
    使Full GC所需時間減少,但老年代會很快被存活物件填滿,Full GC頻率增加。

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

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

2.為什麼要設定兩個Survivor區

  設定兩個Survivor區最大的好處就是解決了碎片化。
  下面來分析一下,為什麼一個Survivor區不行?假設現在只有一個survivor區,一旦Eden滿了,觸發一次Minor GC,Eden中的存活物件就會被移動到Survivor區,這樣繼續迴圈下去。問題來了,進行Minor GC時,Eden和Survivor各有一些存活物件,把Eden區的存活物件放到Survivor區,Survivor區的過期物件移除,很明顯操作之後Survivor區物件所佔有的記憶體是不連續的,也就導致了記憶體碎片化。
  碎片化帶來的風險是極大的,嚴重影響JAVA程式的效能。堆空間被散佈的物件佔據不連續的記憶體,最直接的結果就是,堆中沒有足夠大的連續記憶體空間,就會觸發Major GC。
  那麼,如果建立兩塊Survivor區,剛剛新建的物件在Eden中,經歷一次Minor GC,Eden中的存活物件就會被移動到第一塊survivor space S0,Eden被清空;等Eden區再滿了,就再觸發一次Minor GC,Eden和S0中的存活物件又會被複制送入第二塊survivor space S1(這種複製演算法保證了S1中來自S0和Eden兩部分的存活物件佔用連續的記憶體空間,避免了碎片化的發生)。S0和Eden被清空,然後下一輪S0與S1交換角色,如此迴圈往復。如果物件的複製次數達到閾值,該物件就會被送到老年代中。
  上述機制最大的好處就是,整個過程中,永遠有一個survivor space是空的,另一個非空的survivor space無碎片。