2019獨角獸企業重金招聘Python工程師標準>>>
java的垃圾回收機制是java語言的一大特色,解放了開發人員對內存的復雜控制,但如果你想要一個高級java開發人員,還是需要知道其機制,所謂不僅要會用還要知道其原理這樣才能用的更好,在你的項目出現瓶頸時你才有優化的思路和方向。
這里再簡單說一下回收算法和收集器的關系,好多人搞不明白,可以這樣簡單理解,算法是理論,收集器是根據各自算法理論的實現。
Serial(串行)收集器,這個是jdk1.3.1以前的版本唯一的垃圾收集器。從名字大概可以看出其是單線程,更讓你郁悶的是他還是阻塞的(意味著,它執行時會暫停其它工作的線程),但它的單cpu執行效率是最高的,因為他沒有多線程并行或者并發的管理開銷。適用場景:小型應用
Parallel(并行)收集器,相比Serial收集器,Parallel最主要的優勢在于使用多線程去完成垃圾清理工作,這樣可以充分利用多核的特性,大幅降低gc時間,這里注意一點,它和Serial收集器一樣是執行時,會先暫停業務線程。適合大吞吐量的應用,但對cpu資源比較敏感,需要衡量。適用場景:大型應用,科學計算,大規模數據采集等。
CMS(并發)Concurrent Low Pause Collector收集器,它是一種以獲取最短回收停頓時間為目標的收集器。優點:并發收集,低停頓。基于“標記-清除”算法。目前很大一部分Java應用都集中在互聯網站或B/S系統的服務端上,這類應用尤其重視服務的響應速度,希望系統停頓時間最短,以給用戶帶來較好的體驗,CMS收集器就非常符合這類應用的需求。適應場景:服務器、電信領域等。
?G1垃圾收集器在JDK7 update 4之后對大于4G的堆有了更好的支持,G1是一個針對多處理器大容量內存的服務器端的垃圾收集器,其目標是在實現高吞吐量的同時,盡可能的滿足垃圾收集暫停時間的要求。G1在執行一些Java堆空間中的全區域操作
JDK11,新增Epsilon垃圾收集器,Epsilon 垃圾收集器被稱為“no-op”收集器,將處理內存分配而不實施任何實際的內存回收機制。 Epsilon 的使用案例包括測試性能,內存壓力和虛擬機界面。 它也可以用于短期工作。(未確定)
常見的幾種垃圾回收算法:
標記-清除算法(Mark-Sweep)
首先標記出所有需要回收的對象,在標記完成后統一回收掉所有被標記的對象。它主要由兩個缺點:一個是效率問題,標記和清除過程的效率都不高;另一個是空間問題,標記清除之后會產生大量不連續的內存碎片,空間碎片太多可能會導致當程序在以后的運行過程中需要分配較大對象時無法找到足夠的連續內存而不得不提前觸發另一次垃圾收集動作
復制算法(Copying)(針對新生代)
為了解決標記清除算法的效率問題,出現了復制算法,它將可用內存按容量劃分為大小相等的兩塊,每次使用其中的一塊。當這塊的內存用完了,就將還存活著的對象復制到另一塊上面,然后再把已使用過的內存空間一次清理掉。優點是每次都是對其中的一塊進行內存回收,內存分配時就不用考慮內存碎片等復雜情況,只要移動堆頂指針,按順序分配內存即可,實現簡單,運行高效。缺點是將內存縮小為原來的一半
標記-整理算法(Mark-Compact)(針對老年代)
標記過程仍然與“標記-清除”算法一樣,但后續步驟不是直接對可回收對象進行清理,而是讓所有存活的對象都向一端移動,然后直接清理掉端邊界以外的內存。是復制算法的升級。
分代收集算法(Generational Collection)
分代收集算法(Generational Collection)
當前商業虛擬機的垃圾收集都采用“分代收集”算法,這種算法并無新的方法,只是根據對象的存活周期的不同將內存劃分為幾塊,一般是把Java堆分為新生代和老年代,這樣就可以根據各個年代的特點采用最適當的收集算法。在新生代中,每次垃圾收集時都發現有大批對象死去,只有少量存活,那就選用復制算法,只需要付出少量存活對象的復制成本就可以完成收集。而老年代中因為對象存活率高、沒有額外空間對它進行分配擔保,就必須使用“標記-清理”或“標記-整理”算法來進行回收。
jdk1.7 默認垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代)
jdk1.8 默認垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代)
jdk1.9 默認垃圾收集器G1
?