1. 程式人生 > >垃圾回收

垃圾回收

整體 height 應該 可用 內存回收 mod 有用 生命 tracing

如何判斷一個對象是可回收的? Java虛擬機采用可達性分析算法來判斷對象是否存活。算法基本思想:通過一系列稱為“GC Roots”的對象作為起點,從這些節點開始向下搜索,搜索鎖走過的路徑稱為引用鏈,當一個對象到GC Roots沒有任何引用鏈相連時,證明此對象是不可用的,將會被判定為可回收對象。
可作為GC Roots的對象:
虛擬機棧(棧幀中的局部變量表)中引用的對象
方法區中類靜態屬性引用的對象
方法區中常量引用的對象
本地方法棧中JNI(native方法)引用的對象

強引用、軟引用、弱引用、虛引用 強引用(Strong Reference)
:類似Object obj = new Object)的引用,存在強引用的對象,永遠不會被GC。
軟引用(Soft Reference):還有用但是非必須的對象。只存在軟引用的對象,只有在內存不足時才被GC。可用來實現緩存(還沒有被回收,直接獲取對象),JDK中java.lang.ref.SoftReference用來實現軟引用
弱引用(Weak Reference):具有弱引用的對象具有更短的生命周期。只具有弱引用的對象,在垃圾收集器時會立即被回收,不管內存是否充足。JDK中java.lang.ref.WeakReference用來實現弱引用
虛引用(Phantom Reference)
:一個對象是否有虛引用的存在不會影響對象的生命周期,也無法通過虛引用來獲取一個對象的實例。唯一的用處:能在對象被GC時收到系統通知。JDK中java.lang.ref.PhantomReference用來實現虛引用


垃圾收集算法 標記-清除算法:先標記所有要回收的對象,標記完成後統一回收。不足之處:標記清除效率較低;標記清除後會產生大量不連續的內存碎片,在後續為較大對象分配內存時,無法找到足夠的連續內存而不得不再觸發一次GC。
復制算法:將堆內存分為新生代和老年代,新生代分為一塊較大的Eden空間和兩塊較小的Survivor空間,每次使用Eden和其中一塊Survivor空間。當回收時,將Eden和Survivor中還存活著的對象一次性復制到另一塊Survivor空間上,最後清理掉Eden和使用過的Survivor空間。解決了內存碎片問題。不足之處:在對象存活率較高時要進行較多的復制操作,效率會變低,如果第二塊Survivor沒有足夠空間存放,需要依賴於其他內存(老年代)。
標記-整理算法
:先標記所有要回收的對象,然後讓存活的對象向一端移動,最後清理端邊界意外的內存。
分代收集算法:對新生代和老年代采用不同的垃圾收集算法。新生代中每次垃圾收集時都發現有大量對象死去,只有少量對象存活,采用復制算法。老年代中對象存活率高,且沒有額外空間進行分配擔保,采用標記-清除算法或標記-整理算法。

垃圾收集器 Serial收集器:是一個單線程收集器,在進行垃圾回收時,必須暫停其他所有的工作線程,直到收集結束。試用於單個CPU的環境,由於沒有線程交互的開銷,收集效率高。(適用於在Client模式下運行的虛擬機)
ParNew收集器:是Serial收集器的多線程版本。是運行在Server模式下的虛擬機首選的新生代收集器,原因是除了Serial收集器外,目前只有它能與CMS收集器配合工作。
Parallel Scavenge收集器:是一個新生代收集器,使用復制算法。主要用於控制垃圾收集的吞吐量,可以通過參數精確的控制吞吐量,分別是控制最大垃圾收集停頓時間和吞吐量大小。常被稱為“吞吐量優先”收集器。
Serial Old收集器:是serial收集器的老年代版本,也是一個單線程收集器,使用標記-整理算法。此收集器同Serial收集器一樣,主要用於給Client模式下的虛擬機使用,如果在Server模式下使用,主要有兩大用途:一是在JDK1.5之前與Parallel Scavenge收集器搭配使用;二是作為CMS收集器的後備方案,在並發收集器發生Concurrent Mode Failure時使用。
Parallel Old收集器:是Parallel Scavenge收集器的老年代版本,使用多線程和標記-整理算法。在JDK1.6之後可以和Parallel Scavenge收集器組合使用。
CMS收集器:(Concurrent Mark Sweep)是一種以獲取最短回收停頓時間為目標的收集器,是基於標記 -清除算法實現的。運作過程分為4個步驟:
初始標記:標記GC Roots能直接關聯到的對象,速度很快。
並發標記:進行GC Roots Tracing。即從GC Toots向下搜索並標記沒有引用鏈的對象。
重新標記:修正並發標記期間因用戶程序繼續運作而導致標記產生變動的那一部分對象的標記記錄。此階段停頓時間會比初始標記階段稍長,但遠比並發標記的時間短。
並發清除:清除對象的過程。 其中初始標記和重新標記仍要暫停所有線程。整個過程中耗時最長的並發標記和並發清除過程收集器 線程都可以和用戶線程一起工作,從整體上來說CMS收集器的內存回收過程與用戶線程是並發執行的。 CSM收集器的缺點:
1、CMS收集器對CPU資源非常敏感。CMS默認啟動的垃圾收集器線程數是(CPU數量+3)/4,當CPU數量較少時,垃圾收集器會占用大量CPU資源,導致用戶線程執行速度降低,應用程序吞吐量降低。 2、CMS收集器無法處理浮動垃圾(CMS在並發清除階段用戶線程仍在運行,可能會產生新的垃圾,只能等待下一次GC時處理)。CMS收集器需要預留足夠的內存給用戶線程使用,因此不能等到老年代幾乎滿了再進行收集。JDK1.6之後,CMS收集器啟動閾值設置為92%,即老年代使用了92%之後就啟動CMS收集器。當CMS運行期間預留的內存無法滿足程序的需要時,會出現“Concurrent Mode Failure”失敗,這時會啟用後備方案:臨時啟動Serial Old收集器來進行老年代垃圾回收。 3、CMS是基於標記-清除算法實現的,收集結束會產生大量空間碎片,可能會出現老年代還有大量空間剩余,但是無法找到足夠大連續空間來為新對象分配內存,而不得不再觸發一次Full GC。CMS提供了一個整理碎片的參數,默認開啟,用於在CMS需要在Full GC時開啟內存碎片的合並整理過程,內存整理過程無法並發執行,導致用戶線程停頓時間變長。

G1收集器
GC的過程,GC對程序有什麽影響?當發現虛擬機頻繁GC時應該怎麽辦? GC進行時必須停頓所有Java執行線程(Stop the world)

垃圾回收