一、分代復制垃圾回收
不同的對象的生命周期是不一樣的。因此,不同生命周期的對象可以采取不同的收集方式,以便提高回收效率。 在Java程序運行的過程中,會產生大量的對象,其中有些對象是與業務信息相關,比如Http請求中的
Session對象、線程、Socket連接,這類對象跟業務直接掛鈎,因此生命周期比較長。但是還有一些對象,主要是程序運行過程中生成的臨時變量,這些對象生命周期會比較短,比如:String對象,由於其不變類的特性,系統會產生大量的這些對象,有些對象甚至只用一次即可回收。如果每次垃圾回收都是對整個堆空間進行回收,花費時間相對會 長,並且生命周期長的對象依舊存在,因此引入分代回收,把不同生命周期的對象放在不同代上,不同代上采用最適合它的垃圾回收方式進行回收。
虛擬機中的共划分為三個代:年輕代(Young Generation)、年老點(Old Generation)和持久代(Permanent Generation)。由於對象進行了分代處理,因此垃圾回收區域、時間也不一樣。GC有兩種類型:Scavenge GC和Full GC。
Scavenge GC:一般情況下,當新對象生成,並且在Eden申請空間失敗時,就會觸發Scavenge GC,對Eden區域進行GC,清除非存活對象,並且把尚且存活的對象移動到Survivor區。然后整理Survivor的兩個區。這種方式的GC是對年輕代的Eden區進行,不會影響到年老代。因為大部分對象都是從Eden區開始的,同時Eden區不會分配的很大,所以Eden區的GC會頻繁進行。因而,一般在這里需要使用速度快、效率高的算法,使Eden去能盡快空閑出來。
Full GC :對整個堆進行整理,包括Young、Tenured和Perm。Full GC因為需要對整個對進行回收,所以比ScavengeGC要慢,因此應該盡可能減少Full GC的次數。在對JVM調優的過程中,很大一部分工作就是對於FullGC的調節。有如下原因可能導致Full GC:
· 年老代(Tenured)被寫滿
· 持久代(Perm)被寫滿
· System.gc()被顯示調用
上一次GC之后Heap的各域分配策略動態變化
二、標記垃圾回收
它是第一個可以回收被循環引用的數據結構的垃圾回收算法.現在仍舊有許多常用的垃圾回收技術使用各種各樣的標記清除算法的變體。
在使用標記清除算法時,未引用對象並不會被立即回收.取而代之的做法是,垃圾對象將一直累計到內存耗盡為止.當內存耗盡時,程序將會被掛起,垃圾回收開始執行.當所有的未引用對象被清理完畢時,程序才會繼續執行。
標記清除算法由兩個階段組成:
① 標記階段,標記所有的可訪問對象。
② 收集階段,垃圾收集算法掃描堆並回收所有的未標記對象。
標記垃圾回收的優點:標記清除式的垃圾回收跟蹤了由根(root)訪問的所有對象,所以即使是在有循環引用時,它也可以正確地標記並執行垃圾回收工作。另外,對於引用對象的常規操作不會產生任何的額外開銷。
缺點:當垃圾回收算法執行時,正常的程序會被掛起。特別是,如果一個程序是交互式程序或者正在有一些實時運算時,這就會成為一個問題。比如,一個正在進行垃圾回收的交互式程序會周期的無響應。
三、增量垃圾回收
對這種垃圾回收機制始終無法理解透徹,只能在此稍作解釋,具體該如何定義也請自行google。
簡單地說,它的存在是為了解決標記清除的長停頓問題。增量回收是將GC分成幾部分來執行。設置「GC最多中斷10ms」這樣的條件限制來使GC的終端時間視作可預測的。但是,在兩段的GC程序之間,引用關系可能發生了變化。所以,這種GC算法也要寫屏障,來記錄引用關系的變化。雖然這種方式控制了中斷最高時間,但是由於中斷次數增加,GC總時間是增加的。