Java垃圾回收機(jī)制可以用 3 個(gè)詞來概括: where既荚, when 和 how?
When: 對(duì)象何時(shí)需要被回收的栋艳? 也就是何時(shí)回收無效對(duì)象恰聘, 已死對(duì)象的?
這里涉及到兩種做法: 引用計(jì)數(shù)法和可達(dá)性分析算法吸占。 這里還涉及到 java
中 4 種引用方式: 強(qiáng)引用晴叨, 軟引用, 弱引用和虛引用矾屯, 其引用強(qiáng)度越來越來低兼蕊,
意味著引用越弱的對(duì)象越容易被垃圾回收的。
這 4 種級(jí)別由高到低依次為: 強(qiáng)引用件蚕、 軟引用遍略、 弱引用和虛引用
強(qiáng)引用(StrongReference)
強(qiáng)引用是使用最普遍的引用。 如果一個(gè)對(duì)象具有強(qiáng)引用骤坐, 那垃圾回收器絕不會(huì)回收它。 當(dāng)內(nèi)存空間不足下愈, Java 虛擬機(jī)寧愿拋出 OutOfMemoryError 錯(cuò)誤纽绍,使程序異常終止, 也不會(huì)靠隨意回收具有強(qiáng)引用的對(duì)象來解決內(nèi)存不足的問題势似。
強(qiáng)引用其實(shí)也就是我們平時(shí) A a = new A()這個(gè)意思拌夏。
軟引用(SoftReference)
如果一個(gè)對(duì)象只具有軟引用僧著, 則內(nèi)存空間足夠, 垃圾回收器就不會(huì)回收它障簿;如果內(nèi)存空間不足了盹愚, 就會(huì)回收這些對(duì)象的內(nèi)存。 只要垃圾回收器沒有回收它站故,該對(duì)象就可以被程序使用皆怕。 軟引用可用來實(shí)現(xiàn)內(nèi)存敏感的高速緩存(下文給出示例) 。
軟引用可以和一個(gè)引用隊(duì)列(ReferenceQueue) 聯(lián)合使用西篓, 如果軟引用所引用的對(duì)象被垃圾回收器回收愈腾, Java 虛擬機(jī)就會(huì)把這個(gè)軟引用加入到與之關(guān)聯(lián)的引用隊(duì)列中。
示例: 實(shí)現(xiàn)學(xué)生信息查詢操作時(shí)有兩套數(shù)據(jù)操作的方案岂津。
一虱黄、 將得到的信息存放在內(nèi)存中, 后續(xù)查詢則直接讀取內(nèi)存信息(優(yōu)點(diǎn):讀取速度快吮成; 缺點(diǎn): 內(nèi)存空間一直被占橱乱, 若資源訪問量不高, 則浪費(fèi)內(nèi)存空間)粱甫。
二泳叠、 每次查詢均從數(shù)據(jù)庫讀取, 然后填充到 TO 返回魔种。 (優(yōu)點(diǎn): 內(nèi)存空間將被 GC 回收析二, 不會(huì)一直被占用; 缺點(diǎn): 在 GC 發(fā)生之前已有的 TO 依然存在节预,但還是執(zhí)行了一次數(shù)據(jù)庫查詢叶摄, 浪費(fèi) IO) 。
可以通過軟引用來解決
弱引用(WeakReference)
引用與軟引用的區(qū)別在于: 只具有弱引用的對(duì)象擁有更短暫的生命周期安拟。
在垃圾回收器線程掃描它所管轄的內(nèi)存區(qū)域的過程中蛤吓, 一旦發(fā)現(xiàn)了只具有弱引用的對(duì)象, 不管當(dāng)前內(nèi)存空間足夠與否糠赦, 都會(huì)回收它的內(nèi)存会傲。 不過, 由于垃圾回收器是一個(gè)優(yōu)先級(jí)很低的線程拙泽, 因此不一定會(huì)很快發(fā)現(xiàn)那些只具有弱引用的對(duì)象淌山。
弱引用可以和一個(gè)引用隊(duì)列(ReferenceQueue) 聯(lián)合使用, 如果弱引用所引用的對(duì)象被垃圾回收顾瞻, Java 虛擬機(jī)就會(huì)把這個(gè)弱引用加入到與之關(guān)聯(lián)的引用隊(duì)列中泼疑。
虛引用(PhantomReference)
“虛引用”顧名思義, 就是形同虛設(shè)荷荤, 與其他幾種引用都不同退渗, 虛引用并不會(huì)決定對(duì)象的生命周期移稳。 如果一個(gè)對(duì)象僅持有虛引用, 那么它就和沒有任何引用一樣会油, 在任何時(shí)候都可能被垃圾回收器回收个粱。
虛引用主要用來跟蹤對(duì)象被垃圾回收器回收的活動(dòng)。 虛引用與軟引用和弱引用的一個(gè)區(qū)別在于: 虛引用必須和引用隊(duì)列 (ReferenceQueue) 聯(lián)合使用翻翩。當(dāng)垃圾回收器準(zhǔn)備回收一個(gè)對(duì)象時(shí)都许, 如果發(fā)現(xiàn)它還有虛引用, 就會(huì)在回收對(duì)象的內(nèi)存之前体斩, 把這個(gè)虛引用加入到與之關(guān)聯(lián)的引用隊(duì)列中梭稚。
多引用類型的可達(dá)性判斷
比較容易理解的是 Java 垃圾回收器會(huì)優(yōu)先清理可達(dá)強(qiáng)度低的對(duì)象。
那現(xiàn)在問題來了絮吵, 若一個(gè)對(duì)象的引用類型有多個(gè)弧烤, 那到底如何判斷它的可
達(dá)性呢? 其實(shí)規(guī)則如下: (“單弱多強(qiáng)” )
- 單條引用鏈的可達(dá)性以最弱的一個(gè)引用類型來決定蹬敲;
- 多條引用鏈的可達(dá)性以最強(qiáng)的一個(gè)引用類型來決定暇昂;
我們假設(shè)圖 2 中引用①和③為強(qiáng)引用, ⑤為軟引用伴嗡, ⑦為弱引用急波, 對(duì)于對(duì)象 5 按照這兩個(gè)判斷原則, 路徑①-⑤取最弱的引用⑤瘪校, 因此該路徑對(duì)對(duì)象 5 的引用為軟引用澄暮。 同樣, ③-⑦為弱引用阱扬。 在這兩條路徑之間取最強(qiáng)的引用泣懊, 于是對(duì)象 5 是一個(gè)軟可及對(duì)象。