版權(quán)聲明:本文為博主原創(chuàng)文章,轉(zhuǎn)載請注明出處,歡迎交流學(xué)習(xí)!
在堆內(nèi)存中存放著Java程序中幾乎所有的對象實(shí)例,堆內(nèi)存的容量是有限的,Java虛擬機(jī)會對堆內(nèi)存進(jìn)行管理,回收已經(jīng)“死去”的對象(即不可能再被任何途徑使用的對象),釋放內(nèi)存。垃圾收集器在對堆內(nèi)存進(jìn)行回收前,首先要做的第一件事就是確定這些對象中哪些還存活著,哪些已經(jīng)死去。Java虛擬機(jī)是如何判斷對象是否可以被回收的呢?
引用計(jì)數(shù)算法
引用計(jì)數(shù)算法的原理是這樣的:給對象添加一個引用計(jì)數(shù)器,每當(dāng)有一個地方引用它時,計(jì)數(shù)器值就加1;當(dāng)引用失效時,計(jì)數(shù)器值就減1;在任何時刻計(jì)數(shù)器的值為0的對象就是不可能再被使用的,也就是可被回收的對象。
引用計(jì)數(shù)算法的效率很高,但是主流的JVM并沒有選用這種算法來判定可回收對象,因?yàn)樗幸粋€致命的缺陷,那就是它無法解決對象之間相互循環(huán)引用的的問題,對于循環(huán)引用的對象它無法進(jìn)行回收。
假設(shè)有這樣一段代碼:
public class Object { public Object instance; public static void main(String[] args) { // 1 Object objectA = new Object(); Object objectB = new Object(); // 2 objectA.instance = objectB; objectB.instance = objectA; // 3 objectA = null; objectB = null; }
程序啟動后,objectA和objectB兩個對象被創(chuàng)建并在堆中分配內(nèi)存,這兩個對象都相互持有對方的引用,除此之外,這兩個對象再無任何其他引用,實(shí)際上這兩個對象已經(jīng)不可能再被訪問(引用被置空,無法訪問),但是它們因?yàn)橄嗷ヒ弥鴮Ψ剑瑢?dǎo)致它們的引用計(jì)數(shù)器都不為0,于是引用計(jì)數(shù)算法無法通知GC收集器回收它們。
實(shí)際上,當(dāng)?shù)?步執(zhí)行時,兩個對象的引用計(jì)數(shù)器值都為1;當(dāng)?shù)?步執(zhí)行時,兩個對象的引用計(jì)數(shù)器都為2;當(dāng)?shù)?步執(zhí)行時,二者都清為空值,引用計(jì)數(shù)器值都變?yōu)?。根據(jù)引用計(jì)數(shù)算法的思想,值不為0的對象被認(rèn)為是存活的,不會被回收;而事實(shí)上這兩個對象已經(jīng)不可能再被訪問了,應(yīng)該被回收。
可達(dá)性分析算法
在主流的JVM實(shí)現(xiàn)中,都是通過可達(dá)性分析算法來判定對象是否存活的。可達(dá)性分析算法的基本思想是:通過一系列被稱為"GC Roots"的對象作為起始點(diǎn),從這些節(jié)點(diǎn)開始向下搜索,搜索走過的路徑稱為引用鏈,當(dāng)一個對象到GC Roots對象沒有任何引用鏈相連,就認(rèn)為GC Roots到這個對象是不可達(dá)的,判定此對象為不可用對象,可以被回收。
在上圖中,objectA、objectB、objectC是可達(dá)的,不會被回收;objectD、objectE雖然有關(guān)聯(lián),但是它們到GC Roots是不可達(dá)的,所以它們將會被判定為是可回收的對象。
在Java中,可作為GC Roots的對象包括下面幾種:
1、虛擬機(jī)棧中引用的對象;
2、方法區(qū)中類靜態(tài)屬性引用的對象;
3、方法區(qū)中常量引用的對象;
4、本地方法棧中Native方法引用的對象。
以上探討了判定對象是否可回收的兩種算法,判定對象是否可回收只是垃圾回收的第一步,接下來還要解決何時回收以及如何回收的問題,在后面的文章中我們來探討這些問題。
版權(quán)聲明:本文為博主原創(chuàng)文章,轉(zhuǎn)載請注明出處,歡迎交流學(xué)習(xí)!
在堆內(nèi)存中存放著Java程序中幾乎所有的對象實(shí)例,堆內(nèi)存的容量是有限的,Java虛擬機(jī)會對堆內(nèi)存進(jìn)行管理,回收已經(jīng)“死去”的對象(即不可能再被任何途徑使用的對象),釋放內(nèi)存。垃圾收集器在對堆內(nèi)存進(jìn)行回收前,首先要做的第一件事就是確定這些對象中哪些還存活著,哪些已經(jīng)死去。Java虛擬機(jī)是如何判斷對象是否可以被回收的呢?
引用計(jì)數(shù)算法
引用計(jì)數(shù)算法的原理是這樣的:給對象添加一個引用計(jì)數(shù)器,每當(dāng)有一個地方引用它時,計(jì)數(shù)器值就加1;當(dāng)引用失效時,計(jì)數(shù)器值就減1;在任何時刻計(jì)數(shù)器的值為0的對象就是不可能再被使用的,也就是可被回收的對象。
引用計(jì)數(shù)算法的效率很高,但是主流的JVM并沒有選用這種算法來判定可回收對象,因?yàn)樗幸粋€致命的缺陷,那就是它無法解決對象之間相互循環(huán)引用的的問題,對于循環(huán)引用的對象它無法進(jìn)行回收。
假設(shè)有這樣一段代碼:
public class Object { public Object instance; public static void main(String[] args) { // 1 Object objectA = new Object(); Object objectB = new Object(); // 2 objectA.instance = objectB; objectB.instance = objectA; // 3 objectA = null; objectB = null; }
程序啟動后,objectA和objectB兩個對象被創(chuàng)建并在堆中分配內(nèi)存,這兩個對象都相互持有對方的引用,除此之外,這兩個對象再無任何其他引用,實(shí)際上這兩個對象已經(jīng)不可能再被訪問(引用被置空,無法訪問),但是它們因?yàn)橄嗷ヒ弥鴮Ψ?,?dǎo)致它們的引用計(jì)數(shù)器都不為0,于是引用計(jì)數(shù)算法無法通知GC收集器回收它們。
實(shí)際上,當(dāng)?shù)?步執(zhí)行時,兩個對象的引用計(jì)數(shù)器值都為1;當(dāng)?shù)?步執(zhí)行時,兩個對象的引用計(jì)數(shù)器都為2;當(dāng)?shù)?步執(zhí)行時,二者都清為空值,引用計(jì)數(shù)器值都變?yōu)?。根據(jù)引用計(jì)數(shù)算法的思想,值不為0的對象被認(rèn)為是存活的,不會被回收;而事實(shí)上這兩個對象已經(jīng)不可能再被訪問了,應(yīng)該被回收。
可達(dá)性分析算法
在主流的JVM實(shí)現(xiàn)中,都是通過可達(dá)性分析算法來判定對象是否存活的??蛇_(dá)性分析算法的基本思想是:通過一系列被稱為"GC Roots"的對象作為起始點(diǎn),從這些節(jié)點(diǎn)開始向下搜索,搜索走過的路徑稱為引用鏈,當(dāng)一個對象到GC Roots對象沒有任何引用鏈相連,就認(rèn)為GC Roots到這個對象是不可達(dá)的,判定此對象為不可用對象,可以被回收。
在上圖中,objectA、objectB、objectC是可達(dá)的,不會被回收;objectD、objectE雖然有關(guān)聯(lián),但是它們到GC Roots是不可達(dá)的,所以它們將會被判定為是可回收的對象。
在Java中,可作為GC Roots的對象包括下面幾種:
1、虛擬機(jī)棧中引用的對象;
2、方法區(qū)中類靜態(tài)屬性引用的對象;
3、方法區(qū)中常量引用的對象;
4、本地方法棧中Native方法引用的對象。
以上探討了判定對象是否可回收的兩種算法,判定對象是否可回收只是垃圾回收的第一步,接下來還要解決何時回收以及如何回收的問題,在后面的文章中我們來探討這些問題。
http://www.cnblogs.com/fangfuhai/p/7197750.html