查找內(nèi)存中不再使用的對象
引用計數(shù)法
引用計數(shù)法就是如果一個對象沒有被任何引用指向嘴高,則可視之為垃圾炮姨。這種方法的缺點就是不能檢測到環(huán)的存在。
public class MyObject {
public Object ref = null;
public static void main(String[] args) {
MyObject myObject1 = new MyObject();
MyObject myObject2 = new MyObject();
myObject1.ref = myObject2;
myObject2.ref = myObject1;
myObject1 = null;
myObject2 = null;
}
}
如果采用的是引用計數(shù)算法:
再回到前面代碼GcDemo的main方法共分為6個步驟:
Step1:GcObject實例1的引用計數(shù)加1,實例1的引用計數(shù)=1殊者;
Step2:GcObject實例2的引用計數(shù)加1,實例2的引用計數(shù)=1验夯;
Step3:GcObject實例2的引用計數(shù)再加1猖吴,實例2的引用計數(shù)=2;
Step4:GcObject實例1的引用計數(shù)再加1挥转,實例1的引用計數(shù)=2海蔽;
執(zhí)行到Step 4,則GcObject實例1和實例2的引用計數(shù)都等于2绑谣。
接下來繼續(xù)結(jié)果圖:
Step5:棧幀中obj1不再指向Java堆党窜,GcObject實例1的引用計數(shù)減1,結(jié)果為1借宵;
Step6:棧幀中obj2不再指向Java堆幌衣,GcObject實例2的引用計數(shù)減1,結(jié)果為1壤玫。
到此豁护,發(fā)現(xiàn)GcObject實例1和實例2的計數(shù)引用都不為0哼凯,那么如果采用的引用計數(shù)算法的話,那么這兩個實例所占的內(nèi)存將得不到釋放楚里,這便產(chǎn)生了內(nèi)存泄露断部。
根搜索算法
這是目前主流的虛擬機都是采用GC Roots Tracing算法,比如Sun的Hotspot虛擬機便是采用該算法腻豌。 該算法的核心算法是從GC Roots對象作為起始點家坎,利用數(shù)學中圖論知識,圖中可達對象便是存活對象吝梅,而不可達對象則是需要回收的垃圾內(nèi)存虱疏。這里涉及兩個概念,一是GC Roots苏携,一是可達性做瞪。
GCroots的節(jié)點:全局性的引用(常量或靜態(tài)屬性)與執(zhí)行上下文(例如棧幀中的局部變量表中)
那么可以作為GC Roots的對象(見下圖):
- 虛擬機棧的棧幀的局部變量表所引用的對象;
- 本地方法棧的JNI所引用的對象右冻;
- 方法區(qū)的靜態(tài)變量和常量所引用的對象装蓬;
關(guān)于可達性的對象,便是能與GC Roots構(gòu)成連通圖的對象纱扭,如下圖:
根搜索算法的基本思路就是通過一系列名為”GC Roots”的對象作為起始點牍帚,從這些節(jié)點開始向下搜索,搜索所走過的路徑稱為引用鏈(Reference Chain)乳蛾,當一個對象到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需要回收的垃圾對象。