GC的對象是沒有存活的對象,判斷沒有存活的對象有兩種常用方法:引用計數(shù)和可達(dá)性分析。

1.1 java的GCRoots引用對象

在 Java 虛擬機(jī)的語境下,垃圾指的是死" />

国产成人精品无码青草_亚洲国产美女精品久久久久∴_欧美人与鲁交大毛片免费_国产果冻豆传媒麻婆精东

15158846557 在線咨詢 在線咨詢
15158846557 在線咨詢
所在位置: 首頁 > 營銷資訊 > 網(wǎng)站運營 > 《Java 虛擬機(jī)原理》5.1 GC垃圾收集及案例分析

《Java 虛擬機(jī)原理》5.1 GC垃圾收集及案例分析

時間:2023-06-27 15:45:01 | 來源:網(wǎng)站運營

時間:2023-06-27 15:45:01 來源:網(wǎng)站運營

《Java 虛擬機(jī)原理》5.1 GC垃圾收集及案例分析:一、GC什么對象

GC的對象是沒有存活的對象,判斷沒有存活的對象有兩種常用方法:引用計數(shù)和可達(dá)性分析。

1.1 java的GCRoots引用對象

在 Java 虛擬機(jī)的語境下,垃圾指的是死亡的對象所占據(jù)的堆空間。

a. 虛擬機(jī)棧中引用的對象。

b. 方法區(qū)中靜態(tài)屬性引用的對象。

c.方法區(qū)中常量引用的對象。

d.本地方法中JNI引用的對象。

說明:當(dāng)前對象到GCRoots中不可達(dá)時候,即會滿足被垃圾回收的可能。這些對象但不是就非死不可,此時只能宣判它們存在于一種“緩刑”的階段,要真正的宣告一個對象死亡。至少要經(jīng)歷兩次標(biāo)記:

第一次:對象可達(dá)性分析之后,發(fā)現(xiàn)沒有與GCRoots相連接,此時會被第一次標(biāo)記并篩選。

第二次:對象沒有覆蓋finalize()方法,或者finalize()方法已經(jīng)被虛擬機(jī)調(diào)用過,此時會被認(rèn)定為沒必要執(zhí)行。

1.2 結(jié)合GC對象回顧java虛擬機(jī)內(nèi)存

說明:a. 虛擬機(jī)棧中引用的對象、b. 方法區(qū)中靜態(tài)屬性引用的對象(b.1基本類型數(shù)據(jù)是存儲在運行時常量池)、c.方法區(qū)中常量引用的對象,d.本地方法中JNI引用的對象,這些對象都存儲在java堆。







圖1 GC對象在java虛擬機(jī)內(nèi)存圖

二、什么時候GC

2.1 判斷沒有存活的對象有兩種常用方法

如何辨別一個對象的存亡是關(guān)鍵問題。

1.引用計數(shù)

每個對象有一個引用計數(shù)屬性,新增一個引用時計數(shù)加1,引用釋放時計數(shù)減1,計數(shù)為0時可以回收。此方法簡單,無法解決對象相互循環(huán)引用的問題。

優(yōu)點:實現(xiàn)簡單,判定效率高效,被actionscript3和python中廣泛應(yīng)用。

缺點:無法解決對象之間的循環(huán)引用問題。







圖2 循環(huán)引用場景

2.可達(dá)性分析

目前 Java 虛擬機(jī)的主流垃圾回收器采取的是可達(dá)性分析算法。該算法的實質(zhì):將一系列 GC Roots 作為初始的存活對象合集(live set),然后從該合集出發(fā),探索所有能夠被該集合引用到的對象,并將其加入到該集合中,這個過程我們也稱之為標(biāo)記(mark)。最終,未被探索到的對象便是死亡的,是可以回收的。

從GC Roots開始向下搜索,搜索所走過的路徑稱為引用鏈。當(dāng)一個對象到GC Roots沒有任何引用鏈相連時,則證明此對象是不可用的不可達(dá)對象。如下圖所示,右側(cè)的對象是到GCRoot時不可達(dá)的,可以判定為可回收對象。







圖3 可達(dá)性分析

思考題:什么是GC Roots?GC Roots與GC對象的關(guān)系?

解答:由堆外指向堆內(nèi)的引用,一般而言,GC Roots 包括(但不限于)下列幾種,Java 方法棧楨中的局部變量已加載類的靜態(tài)變量、JNI handles、已啟動且未停止的 Java 線程。因此,GC Roots是GC對象的引用。

可達(dá)性分析法的問題:在多線程環(huán)境下,其他線程可能會更新已經(jīng)訪問過的對象中的引用,從而造成誤報(將引用設(shè)置為 null)或者漏報(將引用設(shè)置為未被訪問過的對象)。誤報使得Java 虛擬機(jī)損失該次垃圾回收的機(jī)會。漏報則比較麻煩,因為垃圾回收器可能回收事實上仍被引用的對象內(nèi)存。一旦從原引用訪問已經(jīng)被回收了的對象,則很有可能會直接導(dǎo)致 Java 虛擬機(jī)崩潰。

2.2 觸發(fā)GC的動作及時機(jī)

(1)動作:程序調(diào)用System.gc時可以觸發(fā)。

(2)時機(jī):系統(tǒng)自身來決定GC觸發(fā)的時機(jī)

根據(jù)Eden區(qū)和From Space區(qū)的內(nèi)存大小來決定,當(dāng)內(nèi)存大小不足時,則會啟動GC線程并停止應(yīng)用線程,GC又分為 Minor GC 和 Full GC。

Minor GC觸發(fā)條件:① 當(dāng) Eden 區(qū)滿時,觸發(fā) Minor GC。

② 當(dāng) FromSuv 或者 ToSuv 區(qū)滿時,觸發(fā) Minor GC。

Full GC觸發(fā)條件: ① 調(diào)用System.gc時,系統(tǒng)建議執(zhí)行Full GC,但是不必然執(zhí)行

② Heap 的老年區(qū)空間不足

③ Metaspace 空間不足

④ 通過Minor GC后進(jìn)入老年代的平均大小大于老年代的可用內(nèi)存

⑤ 由Eden區(qū)、From Space區(qū)向To Space區(qū)復(fù)制時,對象大小大于To Space可用內(nèi)存,則把該對象轉(zhuǎn)存到老年代,且老年代的可用內(nèi)存小于該對象大小

三、如何進(jìn)行GC

GC算法是內(nèi)存回收的理論方法,而GC垃圾收集器則是是內(nèi)存回收的具體實現(xiàn)。下面的內(nèi)容先講GC常用算法。

3.1 GC算法理論基礎(chǔ)

GC算法是內(nèi)存回收的理論方法。GC常用算法理論有:標(biāo)記-清除算法,標(biāo)記-壓縮算法,復(fù)制算法,分代收集算法。即回收垃圾對象的內(nèi)存共有三種方式,分別為:會造成內(nèi)存碎片的清除、性能開銷較大的壓縮、以及堆使用效率較低的復(fù)制。目前主流的JVM(HotSpot)采用的是分代收集算法。

3.1.1 標(biāo)記清除法

標(biāo)記清除法是垃圾回收算法的思想基礎(chǔ)。標(biāo)記清除算法將垃圾分為兩個階段:標(biāo)記階段和清除階段。

標(biāo)記階段:通過根節(jié)點,標(biāo)記所有從根節(jié)點開始的可達(dá)對象,未標(biāo)記過的對象就是未被引用的垃圾對象。

清除階段:清除所有未被標(biāo)記的對象。







圖4 標(biāo)記清除算法

3.1.2 復(fù)制算法

復(fù)制算法是,將原有的內(nèi)存空間分為兩塊,每次只使用其中一塊,在垃圾回收時,將正在適用的內(nèi)存中存活對象復(fù)制到未使用的內(nèi)存塊,然后清除使用的內(nèi)存塊中所有的對象。







圖5 復(fù)制算法

3.1.3 標(biāo)記壓縮算法

標(biāo)記壓縮算法是一種老年代的回收算法。

標(biāo)記階段:與標(biāo)記清除算法一致,對可達(dá)對象做一次標(biāo)記。

清理階段:為了避免內(nèi)存碎片產(chǎn)生,將所有的存活對象壓縮到內(nèi)存的一端。







圖6 標(biāo)記壓縮算法

四、Java虛擬機(jī)的堆劃分

Java 虛擬機(jī)將堆劃分為新生代老年代。其中,新生代又被劃分為 Eden 區(qū),以及兩個大小相同的 Survivor 區(qū)即FromSuvToSuv。







當(dāng)調(diào)用new 指令時,java虛擬機(jī)在Eden區(qū)中劃出一塊作為存儲對象的內(nèi)存。由于堆空間是線程共享的,因此直接在Eden區(qū)是需要進(jìn)行同步的。new 指令,便可以直接通過指針加法(bump the pointer)來實現(xiàn),即把指向空余內(nèi)存位置的指針加上所請求的字節(jié)數(shù)。

問題1:兩個線程同時new Object1對象,則堆如何劃分內(nèi)存?

解答:由于堆內(nèi)存是線程共享的,同步為兩個線程分別劃分object1的內(nèi)存空間,即有2個object1對象。該技術(shù)被稱為TLABThread Local Allocation Buffer,對應(yīng)虛擬機(jī)參數(shù) -XX:+UseTLAB,默認(rèn)開啟)。

問題2:當(dāng) Eden 區(qū)的空間耗盡了怎么辦?

解答:這個時候Java虛擬機(jī)會觸發(fā)一次Minor GC,來收集新生代的垃圾。存活下來的對象,則會被送到Survivor區(qū)

問題3:新生代的兩個Survivor 區(qū),即FromSuvToSuv有什么用處?

解答:當(dāng)Minor GC時,Eden和FromSuv中的存活對象會被復(fù)制到ToSuv中,然后交換FromSuv和ToSuv指針,以保證下一次Minor GC時,ToSuv還是空的。滿足兩種情況之一,可以使對象移動到老年代:1. Minor GC,存活對象從FromSuv復(fù)制到ToSuv,其對象的age+1,當(dāng)超過(默認(rèn)值)15的時候,轉(zhuǎn)移到老年代;2. 動態(tài)對象,如果survivor空間中相同年齡所有的對象大小總和,大于survivor空間的一半,則年級大于或等于該年級的對象就可以直接進(jìn)入老年代

注意Minor GC只針對新生代進(jìn)行垃圾回收,所以在枚舉 GC Roots 的時候,需要考慮從老年代到新生代的引用。為了避免掃描整個老年代,Java 虛擬機(jī)引入卡表(Card Table)的技術(shù),大致地標(biāo)出可能存在老年代到新生代引用的內(nèi)存區(qū)域。

五、GC案例分析

從一個object1分析該對象在分代垃圾回收算法中的回收軌跡

Minor GC是指發(fā)生在新生代的GC,因為Java對象大多是朝生夕滅,所以Minor GC非常頻繁,一般回收速度也比較快;Full GC是指發(fā)生在老年代的GC,出現(xiàn)Full GC一般會伴隨至少一次的Minor GC,其速度一般比Minor GC慢10倍以上。

步驟1:實例化object1,出生于新生代的Eden區(qū)域;







步驟2Minor GC,object1移動到新生代的Fromsuv區(qū)域,object1還存活。







步驟3Minor GC,通過復(fù)制算法將object1移動到新生代的ToSuv區(qū)域,同時object1的年齡age+1,object1 依然存活;







步驟4Minor GC,在新生代的survivor區(qū)域中,與object1同齡的對象并沒有達(dá)到survivor的一半。因此,通過復(fù)制算法將FromSuv和ToSuv 區(qū)域進(jìn)行互換,object1對象被移動到了新生代的ToSuv,object1 依然存活;







步驟5Minor GC,此時survivor中和object1同齡的對象已經(jīng)達(dá)到survivor的一半以上,object1被移動到了老年代區(qū)域,object1 依然存活。







滿足兩種情況之一,都可以使object1對象移動到老年代:

1. Minor GC,存活于survivor 區(qū)域的object1對象的age+1,當(dāng)超過(默認(rèn)值)15的時候,轉(zhuǎn)移到老年代;注意:minor GC下,步驟2/3/4中的移動/復(fù)制全部Tosuv/Fromsuv區(qū)域的對象。

2. 動態(tài)對象,如果survivor空間中相同年齡所有的對象大小總和,大于survivor空間的一半,則年級大于或等于該年級的對象就可以直接進(jìn)入老年代。

步驟6Full GC會觸發(fā)stop the world。object1存活一段時間后,此時GC Roots不可達(dá)object1,而且此時老年代空間比率已經(jīng)超過了閾值,觸發(fā)了Full GC,此時object1被回收。

注意:object1 被回收的必要條件是 object1 不可達(dá)(GC Roots),即 object1 的引用是弱引用







以上的步驟采用分代垃圾收集的思想,描述object1對象從存活到死亡的過程。新生代:采用復(fù)制算法,老年代:采用標(biāo)記-清除算法或者標(biāo)記-整理算法。

stop the world是一種簡單除暴的方式,即停止其他非垃圾回收線程的工作,直到完成垃圾回收。Java 虛擬機(jī)中的 stop the world 是通過安全點(safepoint)機(jī)制來實現(xiàn)的。當(dāng) Java 虛擬機(jī)收到 Stop-the-world 請求,它便會等待所有的線程都到達(dá)安全點,才允許請求 stop the world 的線程進(jìn)行獨占的工作。安全點的初始目的并不是讓其他線程停下,而是找到一個穩(wěn)定的執(zhí)行狀態(tài)。例如,java執(zhí)行某個JNI本地方法時,不訪問Java對象、調(diào)用Java方法、返回至原Java方法,則Java虛擬機(jī)的堆棧不會發(fā)生改變,所以這段代碼可以作為安全點。因此,Java虛擬機(jī)在這個安全點,可以同時進(jìn)行垃圾回收和執(zhí)行這段代碼。



關(guān)鍵詞:收集,分析,垃圾,虛擬,原理

74
73
25
news

版權(quán)所有? 億企邦 1997-2025 保留一切法律許可權(quán)利。

為了最佳展示效果,本站不支持IE9及以下版本的瀏覽器,建議您使用谷歌Chrome瀏覽器。 點擊下載Chrome瀏覽器
關(guān)閉