上一篇文章 JVM 基本介紹 咱們瞭解了一些基本的 JVM 知識,本篇開始逐步學習垃圾回收,咱們都知道既然叫垃圾回收,那回收的就應該是垃圾,但是咱們怎麼知道哪些對象是垃圾呢? 哪些對象須要被回收? 何時須要回收呢?算法
給每一個對象設置一個計數器,每當該對象被引用時引用計數器加 1,有引用斷開時引用計數減 1。當引用計數爲 0 時表示該對象能夠被回收。學習
這個能夠用數據算法中的圖形表示,對象 A-對象 B-對象 C 都有引用,因此不會被回收,對象 B 因爲沒有被引用,沒有路徑能夠達到對象 B,對象 B 的引用計數就就是 0,對象 B 就會被回收。ui
客觀地說,引用計數算法的實現簡單,斷定效率也很高,在大部分狀況下它都是一個不錯的算法,也有一些比較著名的應用案例,例如微軟公司的 COM(Component Object Model)技術、使用 ActionScript 3 的 FlashPlayer、Python 語言和在遊戲腳本領域被普遍應用的 Squirrel 中都使用了引用計數算法進行內存管理。線程
主流的 Java 虛擬機裏面沒有選用引用計數算法來管理內存,其中最主要的緣由是它很難解決對象之間相互循環引用的問題。由於相互引用,計數器值永遠也不會成爲 0 ,因此永遠達不到被 GC 回收的條件。3d
例以下圖:對象A,對象B 循環引用,沒有其餘的對象引用A和B,則A和B 都不會被回收。code
該算法的原理是:以 GC Roots
的對象做爲起始點,而後以該節點爲基準開始向下搜索,搜索過程當中搜索路徑咱們稱之爲引用鏈,當一個對象到 GC Roots
沒有任何引用鏈鏈接的時候,說明該對象是不可用的。cdn
注意:咱們在 上邊的所說的引用都是指定的強引用關係。對象
由於咱們知道 Java 中存在四種引用對象,根據引用強度(從上至下依次減弱)可依次劃分爲:blog
強引用 Strong Reference
隊列
軟引用 Weak Reference
弱引用 Phantom Reference
虛引用 Soft Reference
詳細的概念你們下去能夠自行查看,此處再也不贅述。
方法區 : 類靜態變量引用的對象
方法區 : 常量引用的對象
虛擬機棧 : 本地變量表中引用的對象
本地方法棧 : JNI (帶 Native 關鍵字)引用的對象
以下圖,對象 D 和根對象之間毫無引用鏈,則會被回收。
因爲這種算法即便存在互相引用的對象,但若是這兩個對象沒法訪問到根對象,仍是會被回收。以下圖:對象 C 和對象 D 互相引用,可是因爲沒法訪問根節點,仍是會被回收。
答案是不必定。
一個對象在真正被回收以前,須要經歷兩次標記過程:
第一次標記:
若是對象在進行可達性分析以後發現沒有與 GC Roots 相鏈接的引用鏈,那它將會被第一次標記而且進行一次篩選,篩選的條件是此對象是否有必要執行 finalize() 方法,此時分兩種狀況:
對象沒有覆蓋 finalize() 方法
finalize() 方法已經被虛擬機調用過
在這兩種狀況下虛擬機都認爲此時沒有必要執行垃圾回收。
第二次標記:
在第一次標記斷定基礎之上,若是斷定爲有必要執行 finalize() 方法,則虛擬機會把這個對象放置到一個叫作 F-Queue 的隊列之中,並在以後用 Finalizer 線程去執行回收。(此處的執行指的是 虛擬機會去觸發這個方法,可是並不保證回收成功,也不承諾會等待他運行結束,由於若是有個別對象在 finalize() 方法中執行緩慢甚至發生死循環的時候,有可能會致使 F-Queue 隊列中的其餘對象發生永久等待,最後致使整個垃圾回收系統崩潰)
引用計數法:簡單高效,可是對於相互循環引用的對象沒法判斷是否應該被回收
可達性分析:目前大多虛擬機廠商採用的垃圾回收算法,經過判斷其餘對象是否和根節點之間存在引用鏈來分析是否應該被回收
不可達的對象不必定會當即被回收