JVM常見GC算法
1.標記-清除算法(Mark-Sweep)
-
算法分爲標記和清除兩個階段:
- 首先標記出所有需要回收的對象,
- 然後回收所有需要回收的對象。
-
缺點:
- 效率問題,標記和清理兩個過程效率都不高。效率不高,需要掃描所有對象,堆越大,GC越慢。(GC的速度跟堆裏的對象成正比)
- 空間問題,標記清理之後會產生大量不連續的內存碎片,空間碎片太多可能會導致後續使用中無法找到足夠的連續內存而提前觸發另一次的垃圾蒐集動作。
存在內存碎片問題。GC的次數越多,碎片越嚴重。
Runtime Stack運行時虛擬機棧----用根搜索算法
棧看作Root
通過根搜索算法,計算出 D、G、F、J、M沒有引用,所以就回收了
2.標記-整理(壓縮)算法(Mark-Compact)
標記過程仍然一樣,但後續步驟不是進行直接清理,而是令所有存活的對象向一端移動,然後直接清理掉這端邊界以外的內存。
- 優點:沒有內存碎片
- 缺點:比Mark-Sweep耗費更多的時間進行compact
3.複製算法(Copying)
將可用內存劃分爲兩塊,每次只是用其中的一塊,當半區內存用完了,僅將還存活的對象複製到另外一塊上面,然後就把原來整塊內存空間一次性清理掉。
這樣使得每次內存回收都是對整個半區的回收,內存分配時也就不用考慮內存碎片等複雜情況,只要移動堆頂指針,按順序分配內存就行,實現簡單,運行高效。
- 缺點:
- 這種算法的代價是將內存縮小爲原來的一半,代價高昂。
- 複製收集算法在對象存活率高的時候,效率有所下降。
現在的商業虛擬機中都是用了這種複製算法來回收新生代(剛new出來的對象都在新生代中)。
- 只需要掃描存活的對象,效率更高
- 不會產生碎片
- 需要浪費額外的內存作爲複製區
- 複製算法非常適合生命週期比較短的對象,因爲
每次GC總能回收大部分的對象,複製的開銷比較
小 - 根據IBM的專門研究,98%的Java對象只會存活1
個GC週期,對這些對象很適合用複製算法。而且
不用1: 1的劃分工作區和複製區的空間 - Oracle Hotspot虛擬機默認eden和survivor的大小比例是8:1:1,也就是每次只有10%的內存是“浪費”的。(被使用的eden+survivor空間叫To Survivor,空閒的10%叫From Survivor)
-
- 將內存分爲一塊較大的eden空間和2塊較少的survivor空間,
- 每次使用eden和其中一塊survivor
- 當回收時將eden和survivor還存活的對象一次性拷貝到另外一塊survivor空間上
- 然後清理掉eden和用過的survivor
如果不想浪費50%的空間,就需要有額外的空間進行分配擔保用於應付半區內存中所有對象都100%存活的極端情況,所以在老年代一般不能直接選用這種算法。