回收分爲兩大塊,一爲搜索,二爲回收。算法
一,搜索spa
GC(Garbage Collector)在回收對象前首先必須發現那些無用的對象,如何去發現定位這些無用的對象?
1,引用計數算法(基本棄用)
引用計數器算法是給每一個對象設置一個計數器,當有地方引用這個對象的時候,計數器+1,當引用失效的時候,
計數器-1,當計數器爲 0 的時候,JVM 就認爲對象再也不被使用,是「垃圾」了。
引用計數器實現簡單,效率高;可是不能解決循環引用問問題(A 對象引用 B 對象,B 對象又引用 A 對象,可是
A,B 對象已不被任何其餘對象引用),同時每次計數器的增長和減小都帶來了不少額外的開銷,因此在 JDK1.1 以後,
這個算法已經再也不使用了。
2,根達搜索算法(目前使用中)
根搜索算法是經過一些「GC Roots」對象做爲起點,從這些節點開始往下搜索,搜索經過的路徑成爲引用鏈
(Reference Chain),當一個對象沒有被 GC Roots 的引用鏈鏈接的時候,說明這個對象是不可用的。
複製代碼
a) 虛擬機棧(棧幀中的本地變量表)中的引用的對象。
b) 方法區域中的類靜態屬性引用的對象。
c) 方法區域中常量引用的對象。
d) 本地方法棧中 JNI(Native 方法)的引用的對象。
複製代碼
二,回收3d
1,標記清除算法
標記—清除算法包括兩個階段:「標記」和「清除」。在標記階段,肯定全部要回收的對象,並作標記。清除階
段緊隨標記階段,將標記階段肯定不可用的對象清除。標記—清除算法是基礎的收集算法,標記和清除階段的效率不
高,並且清除後回產生大量的不連續空間,這樣當程序須要分配大內存對象時,可能沒法找到足夠的連續空間。
2,複製算法
複製算法是把內存分紅大小相等的兩塊,每次使用其中一塊,當垃圾回收的時候,把存活的對象複製到另外一塊上,
而後把這塊內存整個清理掉。複製算法實現簡單,運行效率高,可是因爲每次只能使用其中的一半,形成內存的利用
率不高。如今的 JVM 用複製方法收集新生代,因爲新生代中大部分對象(98%)都是朝生夕死的,因此兩塊內存的比
例不是 1:1(大概是 8:1)。
3,標記整理算法
標記—整理算法和標記—清除算法同樣,可是標記—整理算法不是把存活對象複製到另外一塊內存,而是把存活對
象往內存的一端移動,而後直接回收邊界之外的內存。標記—整理算法提升了內存的利用率,而且它適合在收集對象
存活時間較長的老年代。
4,分代收集(當今最經常使用的方法)
將對象按生命週期不一樣劃分:
年輕代(Young Generation)(Eden,Survivor-s0,Survivor-s1)
年老代(Old Generation)
持久代(Permanent Generation)。(包含應用的類/方法信息, 以及JRE庫的類和方法信息.和垃圾回收基本無關)
1)建立新對象,通常將直接放入新生代Eden區域,大對象將直接放入年老代。
2)當Eden區域內存分配完畢,小Gc觸發,根達性分析的可達對象將進入Survivor區域-s0,並清空Eden區域。不可達對象將直接刪除。
3)當Eden區域再次內存分配完畢時候,小gc觸發,根達性分析的可達對象將進入Survivor-s1區域,同時,Survivor-s0區域觸發小gc,其中可達對象移動到Survivor-s1區域,企鵝年齡+1,並清空Survivor-s0,。
4)Eden又填滿以後,Survivor-s0與Survivor-s1,互換標籤,Eden區域可達對象進入Survivor-s0,Survivor-s1觸發小gc,可達對象進入Survivor-s0,而且年齡+1.
5)重複上述過程,達到必定時候,進入年老代。複製代碼