Java垃圾回收--對(duì)象回收判定(可達(dá)性分析算法&對(duì)象引用)

1 述

  • 對(duì)象的回收判定通常有兩種算法 : 引用計(jì)數(shù)算法和可達(dá)性分析算法。
  • 判定對(duì)象是否存活(需要回收)都與“引用”有關(guān)。

2 引用計(jì)數(shù)算法

  • 給對(duì)象中添加一個(gè)引用計(jì)數(shù)器,每當(dāng)有一個(gè)地方引用它時(shí),計(jì)數(shù)器值就加1;
  • 當(dāng)引用失效時(shí),計(jì)數(shù)器值就減1;
  • 任何時(shí)刻計(jì)數(shù)器為0的對(duì)象就是不可能再被使用的,這時(shí)候變可通知GC收集器回收這些對(duì)象。
  • Java虛擬機(jī)里面沒(méi)有選用引用計(jì)數(shù)算法來(lái)管理內(nèi)存,其中最主要的原因是它很難解決對(duì)象之間相互循環(huán)引用的問(wèn)題
  • 優(yōu)點(diǎn):簡(jiǎn)單,高效,現(xiàn)在的objective-c用的就是這種算法。 缺點(diǎn):很難處理循環(huán)引用,相互引用的兩個(gè)對(duì)象則無(wú)法釋放。(需要開(kāi)發(fā)者自己處理)
ClassA a=new ClassA();
ClassB b=new ClassB();
a.setMethod(b);
b.setMethod(a);

3 可達(dá)性分析算法

  • Java虛擬機(jī)中,是通過(guò)可達(dá)性分析(Reachability Analysis)來(lái)判定對(duì)象是否存活的。
  • 這個(gè)算法的基本思路是通過(guò)一系列稱為“GC Roots”的對(duì)象作為起始點(diǎn),從這些節(jié)點(diǎn)開(kāi)始向下搜索,搜索所走過(guò)的路徑稱為引用鏈(Reference Chain),當(dāng)一個(gè)對(duì)象到GC Roots沒(méi)有任何引用鏈項(xiàng)鏈時(shí),則證明此對(duì)象是不可用的。
160f7b667b1af119.png

GC Roots的對(duì)象
1.虛擬機(jī)棧(棧幀中的局部變量表)中的引用對(duì)象
2.方法區(qū)中類靜態(tài)屬性(靜態(tài)對(duì)象)引用的對(duì)象
3.方法區(qū)中常量(final 修飾的成員對(duì)象)引用的對(duì)象。
4.本地方法棧中JNI(Native)引用的對(duì)象。

PS : 成員對(duì)象(即存儲(chǔ)在堆)的引用的對(duì)象為何不在GC Roots?

4 對(duì)象之引用

引用分為強(qiáng)引用(Strong Reference),軟引用(Soft Reference)弱引用(Weak Reference),虛引用(Phantom Refernce)。

  • 強(qiáng)引用 : 類似Object obj=new Object()這類的引用,只要強(qiáng)引用還在,垃圾收集器永遠(yuǎn)不會(huì)回收掉被引用的對(duì)象。
  • 軟引用 : 軟引用是用來(lái)描述一些有用但非必須的對(duì)象,在系統(tǒng)將要發(fā)生內(nèi)存溢出(OOM)異常之前,將會(huì)把這些對(duì)象列進(jìn)回收范圍之中進(jìn)行二次回收。如果這次回收還沒(méi)有足夠的內(nèi)存,才會(huì)拋出內(nèi)存溢出(OOM)異常。JDK1.2之后提供了SoftReference類來(lái)實(shí)現(xiàn)軟引用。
  • 軟引用主要用來(lái)實(shí)現(xiàn)類似緩存的功能,在內(nèi)存足夠的情況下直接通過(guò)軟引用取值,無(wú)需從繁忙的真實(shí)來(lái)源獲取數(shù)據(jù),提升速度;當(dāng)內(nèi)存不足時(shí),自動(dòng)刪除這部分緩存數(shù)據(jù),從真正的來(lái)源獲取這些數(shù)據(jù)。
Object obj = new Object();
SoftReference<Object> sf = new SoftReference<Object>(obj);
  • 弱引用 : 弱引用也是用來(lái)描述非必需對(duì)象的,但是它的引用比軟引用更弱一些,被弱引用關(guān)聯(lián)的對(duì)象只能生存到下一次垃圾收集發(fā)生之前,當(dāng)垃圾收集器工作時(shí),無(wú)論當(dāng)前內(nèi)存是否足夠,都會(huì)被回收。JDK1.2之后提供了SoftReference類來(lái)實(shí)現(xiàn)軟引用。
Object obj = new Object();
WeakReference<Object> wf = new WeakReference<Object>(obj);
  • 虛引用 : 虛引用也成為幽靈引用或者幻影引用,它是最弱的一種引用關(guān)系。無(wú)法通過(guò)虛引用來(lái)取得一個(gè)對(duì)象的實(shí)例。為一個(gè)對(duì)象設(shè)置虛引用的唯一目的就是能夠在這個(gè)對(duì)象被回收的時(shí)候收到一個(gè)系統(tǒng)通知。
Object obj = new Object();
PhantomReference<Object> pf = new PhantomReference<Object>(obj);

5 方法區(qū)的回收

  • 因?yàn)榉椒▍^(qū)主要存放永久代對(duì)象,而永久代對(duì)象的回收率比新生代差很多,因此在方法區(qū)上進(jìn)行回收性價(jià)比不高。
  • 主要是對(duì)常量池的回收和對(duì)類的卸載。
  • 類的卸載條件很多,需要滿足以下三個(gè)條件,并且滿足了也不一定會(huì)被卸載:
  • 該類所有的實(shí)例都已經(jīng)被回收,也就是 Java 堆中不存在該類的任何實(shí)例。
  • 加載該類的 ClassLoader 已經(jīng)被回收。
  • 該類對(duì)應(yīng)的 java.lang.Class 對(duì)象沒(méi)有在任何地方被引用,也就無(wú)法在任何地方通過(guò)反射訪問(wèn)該類方法。
  • 可以通過(guò) -Xnoclassgc 參數(shù)來(lái)控制是否對(duì)類進(jìn)行卸載。
  • 在大量使用反射、動(dòng)態(tài)代理、CGLib 等 ByteCode 框架、動(dòng)態(tài)生成 JSP 以及 OSGo 這類頻繁自定義 ClassLoader 的場(chǎng)景都需要虛擬機(jī)具備類卸載功能,以保證不會(huì)出現(xiàn)內(nèi)存溢出。

6 finalize()

  • finalize() 類似 C++ 的析構(gòu)函數(shù),用來(lái)做關(guān)閉外部資源等工作。
  • 但是 try-finally 等方式可以做的更好,并且該方法運(yùn)行代價(jià)高昂,不確定性大,無(wú)法保證各個(gè)對(duì)象的調(diào)用順序,因此最好不要使用。
  • 當(dāng)一個(gè)對(duì)象可被回收時(shí),如果需要執(zhí)行該對(duì)象的 finalize() 方法,那么就有可能通過(guò)在該方法中讓對(duì)象重新被引用,從而實(shí)現(xiàn)自救。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容