文中討論的GC原理均基於 Sun Hotspot JVM,對於不一樣 JVM 實現可能會有不一樣。算法
決定哪些內存須要回收(物理內存的位置)。框架
決定什麼時候回收這些內存。線程
決定以什麼方式(算法)回收這些內存代理
##2. GC 回收的不一樣區域code
##3. GC 回收對象 的依據 : 對象存活算法對象
引用計數算法接口
每一個對象關聯一個引用計數器,當有引用就加1,引用失效時減一,引用爲0說明對象可回收
對象循環互相引用不能檢測,指的是,多個對象之間互相引用,可是這多個對象與其餘外界再也不具有任何訪問條件的現象
根搜索算法生命週期
從一系列 GCRoot 對象向下搜索,搜索走過的路徑叫作引用鏈,當某個對象不能經過引用鏈被搜索到,就說明可回收
總結隊列
大多數虛擬機採用的是跟搜索算法
##3. GC 引用的分類內存
強引用
使用 new 關鍵字實例化賦值的對象與變量之間的關係叫作強引用
只要強引用存在,就永遠不會被回收
軟引用
描述有做用,但非必需的對象,使用 SoftReference 類來定義
在系統發生內存溢出以前,會被歸入回收範圍以內並進行第二次回收
弱引用
比軟引用更弱的引用類型,使用 WeakReference 類來定義
只能存活到下一次垃圾收集發生以前(不管時候內存溢出)
虛引用
最弱的引用類型,虛引用至關於對象的生命週期是透明的(不會延長對象的生命週期),甚至沒法經過虛引用得到對象的實例,惟一的目的就是在被回收的時候收到一個系統通知,使用 PhantomReference 類來定義
至關於不存在,不影響回收時機
##3. GC 回收對象的全過程
堆內存的回收
根據存活算法掃描到某個對象A已經不被引用並進行第一次標記
第一次標記以後,篩選該對象是否有必要執行 finalize() 方法,執行的條件是該對象覆蓋了finalize() 方法,而且finalize() 方法未被調用過。
若是沒有必要執行finalize() 方法
若是有必要執行finalize()方法,該對象被放置到一個F-QUEUE隊列中,並在一個虛擬機線程去執行,執行的過程當中,只保證觸發這個方法,不保證等待方法運行結束(防止時間過長、死循環 致使GC回收機制崩潰)
GC 進行第二次掃描,若是發現再次發現對象A 不被引用,那麼就將執行回收過程;這裏若是對象A在步驟 4 中執行finalize() 方法的時候,在代碼裏面從新與GCRoot引用鏈得到的訪問關係,此次掃描將不會被掃描到,可是由於finalize()已經被執行過了,因此下次一旦被掃描到,就不能再經過finalize()來GC逃逸了
方法區內存的回收
回收特色: 方法區內存主要回收廢棄,不用的 常量,類,接口
回收常量: 加入對於某個常量池中的字符串,已經沒有任何該類型(String)的對象是這個值,也沒有其餘地方引用到了這個字面量,若是這個時候發生內存回收,並且有必要(這個根據情具體實現況判斷什麼是有必要,好比常量的生命時間,常量的使用頻率等),這個常量將被回收
-回收類(包括它的接口,方法名,字段): 1. 該類的實例對象都已經被回收
2. 加載該類的ClassLoader也已經被回收
3. 該類的Class 對象沒有被任何地方引用,也就是沒法經過反射來訪問這個類
4. 當知足了上述3個條件,僅僅是說明能夠回收了,不表明會回收,具體看不一樣虛擬機的限定條件
5. 類回收的主要場景: 對於應用大量 反射,動態代理,CGLib 等bytecode的框架以及場景,動態生成JSP和OSGI等頻繁定義用戶ClassLoader的場景,都有可能產生大量的自動生成的類加載行爲,爲了防止永久區溢出,須要對這種生成的類進行卸載