JVM記憶體模型
詳情參考 簡書 J先生有點兒屁 JVM記憶體模型
詳情參考 csdn Steafan_ 深入了解Java-GC機制
一、JVM記憶體模型分類
JVM記憶體模型從線程次元歸類分為:線程私有記憶體、線程共享記憶體、以及不在堆内的直接記憶體。

(一)直接記憶體
(二)線程私有型記憶體
線程私有型記憶體 由三種:程式寄存器、Java棧、本地方法棧。
(三)線程共享型記憶體
線程共享型記憶體 又分為兩種:Java堆和本地方法區。
JVM-GC機制
Java虛拟機将堆記憶體進行了“分塊處理”,
從廣義上講,在堆中進行垃圾回收分為新生代(Young Generation)和老生代(Old Generation);
從細微之處來看,為了提高Java虛拟機進行垃圾回收的效率,又将新生代分成了三個獨立的區域(這裡的獨立區域隻是一個相對的概念,并不是說分成三個區域以後就不再互相聯合工作了),分别為:Eden區(Eden Region)、From Survivor區(Form Survivor Region)以及To Survivor(To Survivor Region),
而Eden區配置設定的記憶體較大,其他兩個區較小,每次使用Eden和其中一塊Survivor。
GC實作機制-Java虛拟機在什麼地方進行垃圾回收
堆是Java虛拟機進行垃圾回收的主要場所,其次要場所是方法區。
GC實作機制-Java虛拟機具體實作流程
判斷一個類是否“無用”,則需同時滿足三個條件:
(1)、該類所有的執行個體都已經被回收,也就是Java堆中不存在該類的任何執行個體;
(2)、加載該類的ClassLoader已經被回收
(3)、該類對應的java.lang.Class對象沒有在任何地方被引用,無法在任何地方通過反射通路該類的方法。
虛拟機可以對滿足上述3個條件的無用類進行回收,這裡說的是可以回收而不是必然回收。
GC機制流程
虛拟機通過一個對象年齡計數器來判定哪些對象放在新生代,哪些對象應該放在老生代。
如果對象在Eden出生并經過一次Minor GC後仍然存活,并且能被Survivor容納的話,将被移動到Survivor空間中,并将該對象的年齡設為1。
對象每在Survivor中熬過一次Minor GC,年齡就增加1歲,當他的年齡增加到最大值15時,就将會被晉升到老年代中。
虛拟機并不是永遠地要求對象的年齡必須達到MaxTenuringThreshold才能晉升到老年代,如果在Survivor空間中所有相同年齡的對象大小的總和大于Survivor空間的一半,年齡大于或等于該年齡的對象就可以直接進入老年代,無需等到MaxTenuringThreshold中要求的年齡。
GC實作機制-Java虛拟機如何實作垃圾回收機制
(1)、引用計數算法(Reference Counting)
給對象添加一個引用計數器,每當有一個地方引用它時,計數器值就加1;當引用失效時,計數器值就減1;任何時刻計數器為0的對象就是不可能再被使用的,這就是引用計數算法的核心。客觀來講,引用計數算法實作簡單,判定效率也很高,在大部分情況下都是一個不錯的算法。但是Java虛拟機并沒有采用這個算法來判斷何種對象為死亡對象,因為它很難解決對象之間互相循環引用的問題。
(2)、可達性分析算法(Reachability Analysis)
這是Java虛拟機采用的判定對象是否存活的算法。通過一系列的稱為“GC Roots"的對象作為起始點,從這些結點開始向下搜尋,搜尋所走過的路徑稱為引用鍊(Reference Chain),當一個對象到GC Roots沒有任何引用鍊相連時,則證明此對象是不可用的。可作為GC Roots的對象包括:虛拟機棧中引用的對象、方法區中類靜态屬性引用的對象、方法區中常量引用的對象。本地方法棧JNI引用的對象。
在上圖可以看到GC Roots左邊的對象都有引用鍊相關聯,是以他們不是死亡對象,而在GCRoots右邊有幾個零散的對象沒有引用鍊相關聯,是以他們就會别Java虛拟機判定為死亡對象而被回收。
GC實作機制-何為死亡對象?
Java虛拟機在進行死亡對象判定時,會經曆兩個過程。如果對象在進行可達性分析後沒有與GC Roots相關聯的引用鍊,則該對象會被JVM進行第一次标記并且進行一次篩選,篩選的條件是此對象是否有必要執行
finalize()方法
(詳情見finalize的執行過程),如果目前對象沒有覆寫該方法,或者finalize方法已經被JVM調用過都會被虛拟機判定為“沒有必要執行”。
如果該對象被判定為沒有必要執行,那麼該對象将會被放置在一個叫做F-Queue的隊列當中,并在稍後由一個虛拟機自動建立的、低優先級的Finalizer線程去執行它,在執行過程中JVM可能不會等待該線程執行完畢,因為如果一個對象在finalize方法中執行緩慢,或者發生死循環,将很有可能導緻F-Queue隊列中其他對象永久處于等待狀态,甚至導緻整個記憶體回收系統崩潰。如果在finalize方法中該對象重新與引用鍊上的任何一個對象建立了關聯,即該對象連上了任何一個對象的引用鍊,例如this關鍵字,那麼該對象就會逃脫垃圾回收系統;如果該對象在finalize方法中沒有與任何一個對象進行關聯操作,那麼該對象會被虛拟機進行第二次标記,該對象就會被垃圾回收系統回收。值得注意的是finaliza方法JVM系統隻會自動調用一次,如果對象面臨下一次回收,它的finalize方法不會被再次執行。
finalize的執行過程(生命周期)
(1) 首先,大緻描述一下finalize流程:當對象變成(GC Roots)不可達時,GC會判斷該對象是否覆寫了finalize方法,若未覆寫,則直接将其回收。否則,若對象未執行過finalize方法,将其放入F-Queue隊列,由一低優先級線程執行該隊列中對象的finalize方法。執行finalize方法完畢後,GC會再次判斷該對象是否可達,若不可達,則進行回收,否則,對象“複活”。
(2) 具體的finalize流程:
對象可由兩種狀态,涉及到兩類狀态空間,
一是終結狀态空間 F = {unfinalized, finalizable, finalized};
二是可達狀态空間 R = {reachable, finalizer-reachable, unreachable}。