java可达性_java垃圾回收机制--可达性算法
先說一些題外話,Java虛擬機在執行Java程序的過程中會把它所管理的內存劃分為若干個不同的數據區,這些區分為線程私有區和線程共享區
1、線程私有區
a、程序計數器
記錄正在執行的虛擬機字節碼指令地址。此區域是是唯一一個在java虛擬機規范中沒有規定任何OutOfMemoryError情況的區域。
b、Java虛擬機棧
描述的是Java方法執行的內存模型,每個方法在執行的同時會創建一個棧幀
c、本地方法棧
它與虛擬機棧發揮的作用是類似的,它們之間的區別不過是虛擬機棧為虛擬機執行java方法(也就是字節碼)服務,而本地方法棧則為虛擬機使用的Native方法服務。
2、線程共享區
a、Java堆
被所有線程共享的一塊內存區域,也是Java虛擬機所管理的內存中最大的一塊。
b、方法區
用于存儲已被虛擬機加載的類信息、常量、靜態變量、即時編輯器編譯后的代碼等數據,雖然Java虛擬機規范把方法區描述為堆的一個邏輯部分,但是它卻有一個別名Non-Heap(非堆)
下面開始說正題
目前虛擬機基本都是采用可達性算法,為什么不采用引用計數算法呢?下面就說說引用計數法是如何統計所有對象的引用計數的,再對比分析可達性算法是如何解決引用技術算法的不足。先簡單說說這兩個算法:
1、引用計數法(reference-counting):每個對象都有一個引用計數器,當對象被引用一次,計數器就加1,當對象引用時效一次就減,當計數器為0,意味著對象是垃圾對象,可以被GC回收。
2、可達性算法(GC Root Tracing):從GC Root作為起點開始搜索,那么整個連通圖中對象都是活的,對于GC Root無法達到的對象便是垃圾對象,隨時可被GC回收。
采用引用計數算法的系統只需在每個實例對象創建之初,通過計數器來記錄所有的引用次數即可。而可達性算法,則需要再次GC時,遍歷整個GC根節點來判斷是否回收。
下面通過一段代碼來對比說明:
public classGcDemo {public static voidmain(String[] args) {//分為6個步驟
GcObject obj1 = new GcObject(); //Step 1
GcObject obj2 = new GcObject(); //Step 2
obj1.instance= obj2; //Step 3
obj2.instance = obj1; //Step 4
obj1= null; //Step 5
obj2 = null; //Step 6
}
}classGcObject{public Object instance = null;
}
1、引用計數算法
如果采用的是引用計數算法:
再回到前面代碼GcDemo的main方法共分為6個步驟:
Step1:GcObject實例1的引用計數加1,實例1的引用計數=1;
Step2:GcObject實例2的引用計數加1,實例2的引用計數=1;
Step3:GcObject實例2的引用計數再加1,實例2的引用計數=2;
Step4:GcObject實例1的引用計數再加1,實例1的引用計數=2;
執行到Step 4,則GcObject實例1和實例2的引用計數都等于2。
接下來繼續結果圖:
Step5:棧幀中obj1不再指向Java堆,GcObject實例1的引用計數減1,結果為1;
Step6:棧幀中obj2不再指向Java堆,GcObject實例2的引用計數減1,結果為1。
到此,發現GcObject實例1和實例2的計數引用都不為0,那么如果采用的引用計數算法的話,那么這兩個實例所占的內存將得不到釋放,這便產生了內存泄露。
2、可達性算法
這是目前主流的虛擬機都是采用GC Roots Tracing算法,比如Sun的Hotspot虛擬機便是采用該算法。 該算法的核心算法是從GC Roots對象作為起始點,利用數學中圖論知識,圖中可達對象便是存活對象,
而不可達對象則是需要回收的垃圾內存。這里涉及兩個概念,一是GC Roots,一是可達性。
那么可以作為GC Roots的對象(見下圖):
虛擬機棧的棧幀的局部變量表所引用的對象;
本地方法棧的JNI所引用的對象;
方法區的靜態變量和常量所引用的對象;
關于可達性的對象,便是能與GC Roots構成連通圖的對象,如下圖:
從上圖,reference1、reference2、reference3都是GC Roots,可以看出:
reference1-> 對象實例1;
reference2-> 對象實例2;
reference3-> 對象實例4;
reference3-> 對象實例4 -> 對象實例6;
可以得出對象實例1、2、4、6都具有GC Roots可達性,也就是存活對象,不能被GC回收的對象。
而對于對象實例3、5直接雖然連通,但并沒有任何一個GC Roots與之相連,這便是GC Roots不可達的對象,這就是GC需要回收的垃圾對象。
到這里,相信大家應該能徹底明白引用計數算法和可達性算法的區別吧。
再回過頭來看看最前面的實例,GcObject實例1和實例2雖然從引用計數雖然都不為0,但從可達性算法來看,都是GC Roots不可達的對象。
總之,對于對象之間循環引用的情況,引用計數算法,則GC無法回收這兩個對象,而可達性算法則可以正確回收。
總結
以上是生活随笔為你收集整理的java可达性_java垃圾回收机制--可达性算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 后序线索树怎样画图_算法新解刘新宇(二)
- 下一篇: python列表如何修改_如何在pyth