GC(Garbage Collection),java中的垃圾回收機制。
Java虛擬機中進行垃圾回收的場所有兩個,一個是堆,一個是方法區。方法區通常被稱為永久代,垃圾回收的頻率較低,速度也較慢。(JDK1.8之后取消永久代改為Metaspace。元空間並不在虛擬機中,而是使用本地內存)
判斷是否需要被回收
Java虛擬機采用可達性分析法來判斷一個對象是否需要被回收。就是以一系列的稱為“GC Roots"的對象作為起始點,從這些結點開始向下搜索,搜索所走過的路徑稱為引用鏈(Reference Chain),當一個對象到GC Roots沒有任何引用鏈相連時,則證明此對象是不可用的。
GC Roots的對象包括:
- 虛擬機棧中引用的對象;
- 方法區中類靜態屬性引用的對象;
- 方法區中常量引用的對象;
- 本地方法棧JNI引用的對象;
Java虛擬機在進行死亡對象判定時,如果對象在進行可達性分析后沒有與GC Roots相關聯的引用鏈,則該對象會被JVM進行第一次標記並且判斷是否執行finalize方法。
如果當前對象沒有覆蓋該方法,或者finalize方法已經被JVM調用過都會被虛擬機判定為“沒有必要執行”,那么該對象將會被放置在一個叫做F-Queue的隊列當中,由一個低優先級的Finalizer線程去執行它。
如果在finalize方法中該對象重新與引用鏈上的任何一個對象建立了關聯,例如this關鍵字,那么該對象就會逃脫垃圾回收系統;如果該對象在finalize方法中沒有與任何一個對象進行關聯操作,那么該對象會被虛擬機進行第二次標記,該對象就會被垃圾回收系統回收。finaliza方法JVM系統只會自動調用一次,下一次回收,它的finalize方法不會被執行。(躲得了初一,躲不了十五??)
標記清除算法(Mark-Sweep):首先需要標記可以回收的對象內存,然后在對回收的內存進行清除。缺點是容易產生內存碎片,碎片太多可能會導致為大對象分配空間時無法找到足夠的空間而提前觸發GC。

復制算法(Copying):將內存分為兩塊,先只使用其中一塊內存,GC時把存活對象全部復制到另一塊內存上,第一塊內存全部清空。復制算法可以解決碎片問題,但是缺點是會減少可用空間。復制算法如果存活對象多的話,效率會大大降低,所以它是用於新生代的回收算法。(新生代大部分對象都會被回收)

(算法圖片來自https://www.cnblogs.com/dolphin0520/p/3783345.html)
標記整理算法(Mark-Compact):標記后不直接清理可回收內存,而是將存活對象都移動到一端,然后清除掉可回收內存。標記整理算法可以充分的利用空間,用於老年代的垃圾回收。(老年代的特點是存活對象較多,被清理的對象較少。在新生代躲過15次GC之后的對象會被轉入老年代,大對象通常會被直接分配到老年代)
七種垃圾回收器:

Serial: 串行回收器,只使用一個線程進行垃圾回收,會暫停所有用戶線程。對應JVM參數:-XX:+UseSerialGC,啟用Serial(單線程復制)+Serial Old(單線程記整理)的收集器組合。
ParNew: Serial收集器在新生代的並行版本,也會暫停用戶線程。對應JVM參數:-XX:+UseParNewGC,啟用ParNew(多線程復制)+Serial Old(單線程標記整理)的收集器組合 ps:這個組合已經被"不推薦"了。
ParallelScavenge: 並行回收器,也叫吞吐量優先收集器,可配置GC線程數量。Serial收集器在新生代和老年代的並行版本,JAVA8的默認垃圾回收器。對應JVM參數:-XX:+UseParallelGC(互相激活),啟用Parallel(多線程復制)+Parallell Old(多線程標記整理)的收集器組合。
ParallelOld: ParallelScavenge的老年代版本。對應JVM參數:-XX:+ParallelOldGC(與-XX:+UseParallelGC互相激活),啟用Parallel(多線程復制)+Parallel Old(多線程標記整理)的收集器組合。
CMS : 並發標記清除回收器(並發指與用戶進程同時進行),獲取最短停頓時間的收集器,G1出現之前大型應用的首選收集器。對應JVM參數:-XX:+UseConcMarkSweepGC,啟用ParNew(多線程復制)+CMS(並發標記清除)的收集器組合,Parallell Old做為老年代的備用 。
SerialOld: Serial收集器的老年代版本,做為老年代CMS的后備版本。已經被優化很少使用了。
G1:G1垃圾回收器,對應JVM參數:-XX:+UseC1GC,整體上采用標記整理算法,局部采用復制算法,不會產生內存碎片(CMS會產生碎片)。與應用程序並發執行,停頓時間大大減少且可以指定。Java9的默認垃圾收集器。
G1垃圾回收器的原理:將整個堆內存分成大小相同的子區域(Region),子區域沒有代和區的限制,在JVM啟動時會自動設置這些子區域的大小,也可以通過-XX;G1HeapRegionSize=n(1M~32M,且必須是2的冪),默認分為2048個分區(即最大32M*2048=64G內存)。G1仍屬於分代收集,包含新生代的Region,仍會暫停所有線程,將存活的對象復制到老年代的Region。老年代的Region將一個區域復制到另一個區域完成清理。(還會用連續的Humongous區用來存放大對象,有時不得不啟用FullGC)
G1回收器參數配置樣例:-XX:+UseG1GC,-Xmx32g,-XX:MaxGCPauseMillis=100(最大GC停頓單位毫秒,一個軟目標,JVM將盡量停頓小於這個時間)
四種引用類型:
強引用(就算出現了OOM也不會對該對象進行回收,默認是強引用)
軟引用(內存不夠的時候才會回收,使用SoftReference<T>實現)
弱引用(不管內存夠不夠用,GC都會回收,使 用WeakReference<T>實現)
虛引用(使用PhantomReference<T>實現,需要配合ReferenceQueue聯合使用,發生gc后被放入到引用隊列)
ps:虛引用就是用來監控某個對象的回收信息,在gc之后可以進行一個后置通知
ps:mybatis代碼中緩存部分,大量使用了軟引用和弱引用
