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)自救。