Java垃圾回收之標(biāo)記清除算法詳解
java垃圾回收算法之-引用計(jì)數(shù)器,這個(gè)算法其中一個(gè)優(yōu)點(diǎn)便是,實(shí)時(shí)性,只要對(duì)象的引用計(jì)數(shù)器的值為0,則立刻回收。接下來(lái)介紹的標(biāo)記清除算法,當(dāng)對(duì)象的引用計(jì)數(shù)器的值為0時(shí),不會(huì)立刻被回收的。
概念介紹
root對(duì)象
在標(biāo)記清除算法中,會(huì)把如下對(duì)象稱之為root對(duì)象
- 被棧中的變量(棧中存的是對(duì)象的引用)所引用的對(duì)象
- 被static變量引用的對(duì)象
可訪問(wèn)的對(duì)象
如果棧中有一個(gè)變量a引用了一個(gè)對(duì)象,那么該對(duì)象是可訪問(wèn)的,如果該對(duì)象中的某一個(gè)字段引用了另一個(gè)對(duì)象b,那么b也是可訪問(wèn)的??稍L問(wèn)的對(duì)象也稱之為live對(duì)象
標(biāo)記清除算法介紹
該算法有兩個(gè)階段。
1. 標(biāo)記階段:找到所有可訪問(wèn)的對(duì)象,做個(gè)標(biāo)記
2. 清除階段:遍歷堆,把未被標(biāo)記的對(duì)象回收
備注:
- 該算法一般應(yīng)用于老年代,因?yàn)槔夏甏膶?duì)象生命周期比較長(zhǎng)。
標(biāo)記階段算法
偽代碼類似如下:
for each root variable r mark (r); sweep ();
為了能夠區(qū)分對(duì)象是live的,可以為每個(gè)對(duì)象添加一個(gè)marked字段,該字段在對(duì)象創(chuàng)建的時(shí)候,默認(rèn)值是false
假設(shè)有一個(gè)對(duì)象p,p對(duì)象還間接的引用了其他對(duì)象,那么可以使用一個(gè)遞歸算法去進(jìn)行標(biāo)記,例如:
void mark(Object p)
if (!p.marked)
p.marked = true;
for each Object q referenced by p
mark (q);
這個(gè)mark方法只有當(dāng)所有對(duì)象已經(jīng)被mark后才會(huì)退出。
清除階段算法
在這個(gè)階段,需要去遍歷堆中所有對(duì)象,并找出未被mark的對(duì)象,進(jìn)行回收。與此同時(shí),那些被mark過(guò)的對(duì)象的marked字段的值會(huì)被重新設(shè)置為false,以便下次的垃圾回收。
偽代碼如下:
void sweep ()
for each Object p in the heap
if (p.marked)
p.marked = false
else
heap.release (p);
下面用一張圖來(lái)表示標(biāo)記清除算法的整個(gè)過(guò)程。

標(biāo)記清除算法的優(yōu)點(diǎn)和缺點(diǎn)
1. 優(yōu)點(diǎn)
- 是可以解決循環(huán)引用的問(wèn)題
- 必要時(shí)才回收(內(nèi)存不足時(shí))
2. 缺點(diǎn):
- 回收時(shí),應(yīng)用需要掛起,也就是stop the world。
- 標(biāo)記和清除的效率不高,尤其是要掃描的對(duì)象比較多的時(shí)候
- 會(huì)造成內(nèi)存碎片(會(huì)導(dǎo)致明明有內(nèi)存空間,但是由于不連續(xù),申請(qǐng)稍微大一些的對(duì)象無(wú)法做到),如下圖:

解決循環(huán)引用
出現(xiàn)循環(huán)引用的代碼如下:
class TestA{
public TestB b;
}
class TestB{
public TestA a;
}
public class Main{
public static void main(String[] args){
A a = new A();
B b = new B();
a.b=b;
b.a=a;
a = null;
b = null;
}
}
對(duì)應(yīng)的圖如下:

這個(gè)時(shí)候,當(dāng)a = null; b = null;的時(shí)候,圖像變成如下:

那么使用標(biāo)記清除算法是可以回收a和b的,原因是標(biāo)記清除算法是從棧中根對(duì)象開(kāi)始的,改算法走完后,a對(duì)象和b對(duì)象是沒(méi)有被標(biāo)記的,會(huì)被直接回收。
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請(qǐng)查看下面相關(guān)鏈接
相關(guān)文章
Java 反射調(diào)用靜態(tài)方法的簡(jiǎn)單實(shí)例
下面小編就為大家?guī)?lái)一篇Java 反射調(diào)用靜態(tài)方法的簡(jiǎn)單實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-06-06
Java中的鎖與鎖的狀態(tài)升級(jí)詳細(xì)解讀
這篇文章主要介紹了Java中的鎖與鎖的狀態(tài)升級(jí)詳細(xì)解讀,Java 1.6以后官方針對(duì)鎖的優(yōu)化,主要是增加了兩種新的鎖:偏向鎖和輕量級(jí)鎖,再加上本身重量級(jí)鎖,那么鎖基本上可以大致分為這三種,它們之間的區(qū)別主要是體現(xiàn)在等待時(shí)間上面,需要的朋友可以參考下2024-01-01
springBoot 整合ModBus TCP的詳細(xì)過(guò)程
ModBus是一種串行通信協(xié)議,用于從儀器和控制設(shè)備傳輸信號(hào)到主控制器或數(shù)據(jù)采集系統(tǒng),它分為主站和從站,主站獲取和編寫(xiě)數(shù)據(jù),從站則是設(shè)備,本文給大家介紹springBoot 整合ModBus TCP的詳細(xì)過(guò)程,感興趣的朋友一起看看吧2025-01-01
Spring裝配Bean之用Java代碼安裝配置bean詳解
這篇文章主要給大家介紹了關(guān)于Spring裝配Bean之用Java代碼安裝配置bean的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用spring具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-10-10
Java中transient關(guān)鍵字的詳細(xì)總結(jié)
本文要介紹的是Java中的transient關(guān)鍵字,transient是短暫的意思。對(duì)于transient 修飾的成員變量,在類的實(shí)例對(duì)象的序列化處理過(guò)程中會(huì)被忽略,感興趣的朋友可以參考閱讀2023-04-04
Java?List集合取交集的8種不同實(shí)現(xiàn)方式總結(jié)
工作中經(jīng)常遇到需要取兩個(gè)集合之間的交集、差集情況,下面這篇文章主要給大家總結(jié)介紹了關(guān)于Java?List集合取交集的8種不同實(shí)現(xiàn)方式,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-04-04
IDEA無(wú)法使用終端terminal問(wèn)題的解決方案
這篇文章主要介紹了IDEA無(wú)法使用終端terminal問(wèn)題的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09

