一、判斷對象是否已死
1、引用計數算法
給對象中添加一個引用計數器,每當有一個地方引用它時,計數器值就加1,當引用時效時,計數器值就減1;任何時刻計數器為0的對象就是不可能再被使用的,引用計數算法管理記憶體很高效,但是java虛拟機沒有使用,因為是他很難解決對象間互相循環引用的問題。兩個對象互相引用,導緻它們的引用計數都不為0,于是引用計數算法無法通知GC收集器回收它們。、
2、可達性分析算法
Java是通過可達性分析(Reachability Analysis)來判定對象是否存活的。這個算法的基本思路就是通過一系列的稱為“GC Roots” 的對象作為起始點,從這些節點開始向下搜尋,搜尋所走過的路徑稱為引用鍊(Reference Chain),當一個對象到GC Roots沒有任何引用鍊相連時,則證明對象是不可用的。

在Java語言中,可以作為GC Roots的對象包括下面幾種:
虛拟機棧(棧幀中的本地變量表)中引用的對象。
方法區中靜态類屬性引用的對象。
方法區中常量引用的對象。
本地方法棧中JNI(即一般說的Native方法)引用的對象。
二、垃圾收集算法
1、标記-清除算法
最基礎的收集算法是“标記-清除”(Mark-Sweep)算法,算法分為“标記”和“清除”兩個階段:首先标記出所有需要收回的對象,在标記完成之後統一回收所有被标記的對象。它有兩個不足:一個是效率問題,标記和清除兩個過程的效率都不高;另一個是空間問題,标記清除之後會産生大量的不連續的記憶體碎片,空間碎片太多可能會導緻以後在程式運作過程中需要配置設定較大對象時,無法找到足夠的連續記憶體進而不得不提前觸發另一次垃圾收集動作。
2、複制算法
為了解決效率問題,一種稱為“複制”(Copying)的收集算法出現了,它将可用記憶體按容量劃分為大小相等的兩塊,每次隻使用其中的一塊。當這塊的記憶體用完了,就将還存活着的對象複制到另一塊上面,然後再把已使用過的記憶體空間一次清理掉。這樣使得每次都是對整個半區進行記憶體回收,記憶體配置設定時也就不用考慮記憶體碎片等複雜情況,隻要移動堆頂指針,按順序配置設定記憶體即可,實作簡單,運作高效。代價很高,将記憶體縮小為原來的一半。
3、标記-整理算法
“标記-整理”(Mark-Compact)算法,标記過程仍然與“标記-清除”算法一樣,但後續步驟不是直接對可回收對象進行清理,而是讓所有存活的對象都向一端移動,然後直接清理掉端邊界以外的記憶體。
4、分代收集算法
“分代收集”(Generational Collection)算法,根據對象存活周期的不同将記憶體劃分為幾塊。一般是把Java堆分為新生代和老年代,這樣既可以根據各個年代的特點采用最适當的收集算法。在新生代中,每次垃圾收集時都發現有大批對象死去,隻有少量存活,那就選用複制算法,隻需要付出少量對象的複制成本就可以完成收集。而老年代中因為對象存活率高、沒有額外空間對它進行配置設定擔保,就必須使用“标記-清除”或者“标記-整理”算法來進行回收。
三、垃圾收集器
1、Serial收集器
這個收集器時單線程的收集器,它進行來寄收集時,必須暫停其他所有的工作線程,直到它收集結束。
2、ParNew收集器
ParNew收集器是Serial收集器的多線程版本,除了使用多線程進行垃圾收集之外,其餘行為包括Serial收集器可用的所有控制參數、收集算法、Stop The World、對象配置設定規則、回收政策等都與Serial收集器一樣。
3、Parallel Scavenge收集器
Parallel Scavenge收集器是一個新生代收集器,它也是使用複制算法的收集器,又是并行的多線程收集器。Parallel Scavenge收集器的目标是達到一個可控制的吞吐量(Throughput)。所謂的吞吐量就是CPU用于運作使用者代碼的時間與CPU總消耗時間的比值,即吞吐量=運作使用者代碼時間/(運作使用者代碼時間+垃圾收集時間)。
Parallel Scavenge收集器提供了兩個參數用于精确控制吞吐量,分别是控制最大垃圾收集停頓時間的-XX:MaxGCPauseMillis參數以及直接設定吞吐量大小的-XX:GCTimeRatio參數。 Parallel Scavenge收集器還有一個參數:-XX:+UseAdaptiveSizePolicy,這個參數打開之後,就不需要手工指定新生代的小小(-Xms)、Eden與Survivor區的比例(-XX:SurvivorRatio)、晉升老年代對象大小(-XX:PretenureSizeThreshold)等參數了。虛拟機會自動調整,這種方式稱為GC自适應的調節政策(GC Ergonomics)。
4、Serial Old收集器
Serial Old收集器是Serial收集器的老年代版本,是一個單線程收集器,使用“标記-整理”算法。這個收集器的主要意義也是在于給Client模式下的虛拟機使用。如果在Server模式下,那麼它主要還有兩大用途:一種用途是JDK1.5以及之前的版本中與Parallel Scavenge收集器搭配使用,另一種用途是作為CMS收集器的後備預案,在并發收集發生Concurrent Mode Failure時使用。
5、Parallel Old收集器
Parallel Old收集器是Parallel Scavenge收集器的老年代版本,使用多線程和“标記-整理”算法。
6、CMS收集器
CMS(Concurrent Mark Sweep)收集器是一種以擷取最短回收停頓時間為目标的收集器。是基于“标記-清楚”算法實作的,主要有四個運作步驟,包括:初始标記(CMS initial mark),并發标記(CMS concurrent mark),重新标記(CMS remark),并發清除(CMS concurrent sweep)
不支援該協定取消重新上傳
7、G1收集器
G1是一款面向服務端應用的垃圾收集器。G1具備以下特點:并行與并發,分代收集,空間整理,可預測的停頓。使用G1收集器時,Java堆的記憶體布局就與其他收集器有很大差别,它将整個Java堆劃分為多個大小相等的獨立區域(Region),雖然還保留有新生代和老年代的概念,但新生代和老年代不再是實體隔離的了,它們都是一部分Region的集合。
四、記憶體配置設定政策
對象的記憶體配置設定,就是在堆上配置設定,對象主要配置設定在新生代Eden區上。
1、對象優先在Eden配置設定
大多數情況下,對象在新生代Eden區中配置設定。當Eden區沒有足夠空間進行配置設定時,虛拟機将發起一次Minor GC。
2、大對象直接進入老年代
所謂的大對象是指,需要大量連續記憶體空間的Java對象,最典型的就是那種很長的字元串以及數組。虛拟機提供了一個-XX:PretenureSizeThreshold參數,令大于這個設定值的對象直接在老年代配置設定。
3、長期存活的對象将進入老年代
虛拟機給每個對象定義了一個對象年齡計數器,對象在Survivor中每“熬過”一次Minor GC,年齡就增加1歲,當它的年齡達到一定程度,就會晉升到老年代。對象晉升的門檻值,可以通過參數-XX:MaxTenuringThreshold設定。
4、動态對象年齡判定
如果在Survivor空間中相同年齡所有對象的大小的總和大于Survivor空間的一半,年齡大于或者該年齡的對象就可以直接進入老年代,無須等到XX:MaxTenuringThreshold中要求的年齡。
5、空間配置設定擔保
在發生Minor GC之前,虛拟機會先檢查老年代最大可用的連續空間是否大于新生代所有對象空間,如果這個條件成立,那麼Minor GC 可以確定是安全的。如果不成立,則虛拟機會檢視HandlerPromotionFailure設定值是否允許擔保失敗。如果允許,那麼會繼續檢查老年代最大可用的連續空間是否大于曆次晉升到老年代對象的平均大小,如果大于,将嘗試着進行一次Minor GC,盡管這次Minor GC 是有風險的;如果小于,或者HandlerPromotionFailure設定不允許冒險,那麼這時也要改為進行一次Full GC。
本文來自于《深入Java虛拟機-JVM進階特性與最佳實踐》---周志明。如果侵權,請聯系作者删除。
轉載于:https://www.cnblogs.com/hmily555/p/8654155.html