本文部分内容引用自 https://www.cnblogs.com/java-zhao/p/5183261.html
1、三種垃圾回收算法
- 标記-整理法(标記壓縮)(老年代)
- 标記-清除法(老年代)
- 複制算法(新生代)
1.1 标記-清除法

原理:
從根節點集合出發進行掃描,标記出存活的對象,最後掃描整個記憶體空間并清除沒有标記的對象(即死亡對象)
适用場景:
- 對象存活比較多的情況下比較高效
- 适用于老年代
缺點:
- 容易産生記憶體碎片,如果此時再為一個較大的對象配置設定記憶體時,會提前觸發垃圾回收
- 掃描了整個磁盤空間兩次(第一次标記存活對象,第二次清除沒有标記的對象)
1.2 标記-整理法
原理:
從根節點集合出發,标記出存活的對象,最後掃描整個記憶體空間,清除未被标記的對象,清除完畢之後,将所有存活的對象左移到一起。
适用場景:
- 用于老年代
缺點:
- 需要移動對象,若對象非常多且标記回收後的記憶體非常不完整,可能移動這個動作也要花費一定的時間
- 掃描了整個記憶體空間兩次(一次标記,一次清除)
優點:
- 不會産生記憶體碎片
1.3 複制算法
原理:
從根集合進行掃描,标記出所有的存活對象,并且将這些存活對象複制到一塊新的記憶體 區域,然後将原記憶體空間中的對象全部回收。
适用場景:
- 存活對象較少時比較高效
- 掃描了整個記憶體空間一次(标記複活對象并且移動)
- 适用于新生代:98%的對象就是朝生夕死,存活下來的很少
缺點:
- 需要一塊空的記憶體區域
- 需要複制移動對象
1.4 分代收集算法
概述:
目前的商用虛拟機都采用“分代收集”算法,分代收集算法并沒有什麼新的思想。
原理:
根據對象的存活周期的不同将記憶體劃分為新生代和老年代這樣就可以根據各個年代的特性采用最适當的收集算法。新生代中每次垃圾收集都有大量的對象死去,存活的對象隻占少數,是以新生代采用複制算法,隻要付出少量的複制成本就可以完成收集。而老年代中因為對象的存活率較高、沒有額外的空間對他進行配置設定擔保,就必須使用“标記-清除”或者“标記-整理”算法來進行回收。
詳解:
- 一般将Java堆分為新生代和老年代,除此之外,新生代又進一步劃分為Eden區,和Survivor區,Survivor區又被劃分為FromSurvivor 和To Survivor區。在大部分虛拟機中,Eden:From:To = 8:1:1。
- 産生的對象優先配置設定在Eden區内。當Eden區的剩餘記憶體不足以為新的對象配置設定記憶體,或Eden區已滿時,會觸發MinorGC,本次GC會将Eden區中存活的對象複制到FromSurvivor區,如果發現存活下來的對象From區放不下,那麼這些存活下來的對象會通過配置設定擔保機制全部進入老年代,之後将Eden區全部回收掉。
- 之後産生的對象依然被配置設定在Eden區,下次Eden區滿了或者放不下時,會将Eden區和From區中存活的對象全部複制到To區,同理,如果To區的記憶體大小放不下這些存活的對象,那麼這些存活的對象會通過配置設定擔保機制全部進入老年代,即每次進行GC時,From和To區總有一塊區域空閑。
- 當碰到Eden區放不下的大對象(指那些需要大量連續記憶體的對象)時,會直接将大對象放入老年代。這樣做的目的是避免在Eden區及兩個Survivor區之間發生大量的記憶體複制,這樣會降低複制的效率。
- 虛拟機為每個對象定義了一個對象年齡計數器,每“平安度過”一次GC,并且能被Survivor區所容納的話,就将計數器加一。當對象的年齡增加到一定程度(預設為15歲),此對象就會晉升到老年代中。當然,為了更好的适應不同程式的記憶體情況,虛拟機并不是永久得要求對象的年齡必須達到最大年齡限制才能晉升到老年代。如果在Survivor空間中相同年齡的對象大小的總和超過Survivor空間記憶體大小的一半時,年齡大于等于改年齡數值的對象會直接晉升到老年代中去,無需等到最大年齡限制。
2、兩種GC的差別
新生代GC(MinorGC):指發生在新生代的垃圾回收動作,因為大多數Java對象都具備朝生夕滅的的特性,是以Minor GC非常頻繁,一半回收速度也比較快。
老年代GC(Major GC/Full GC):指發生在老年代的GC,出現了Major GC,經常會伴随至少一次的MinorGC。Major GC 的速度一半會比Minor GC慢10倍以上。