溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Java——JVM篇——收藏系列來啦(二)

發(fā)布時(shí)間:2020-07-12 15:02:55 來源:網(wǎng)絡(luò) 閱讀:112 作者:颯拉阿依醬 欄目:編程語言

2.4.垃圾回收與算法
Java——JVM篇——收藏系列來啦(二)
2.4.1. 如何確定垃圾
2.4.1.1.引用計(jì)數(shù)法
在 Java 中,引用和對(duì)象是有關(guān)聯(lián)的。如果要操作對(duì)象則必須用引用進(jìn)行。因此,很顯然一個(gè)簡(jiǎn)單的辦法是通過引用計(jì)數(shù)來判斷一個(gè)對(duì)象是否可以回收。簡(jiǎn)單說,即一個(gè)對(duì)象如果沒有任何與之關(guān)聯(lián)的引用,即他們的引用計(jì)數(shù)都不為 0,則說明對(duì)象不太可能再被用到,那么這個(gè)對(duì)象就是可回收對(duì)象。

2.4.1.2.可達(dá)性分析
為了解決引用計(jì)數(shù)法的循環(huán)引用問題,Java 使用了可達(dá)性分析的方法。通過一系列的“GC roots”對(duì)象作為起點(diǎn)搜索。如果在“GC roots”和一個(gè)對(duì)象之間沒有可達(dá)路徑,則稱該對(duì)象是不可達(dá)的。
要注意的是,不可達(dá)對(duì)象不等價(jià)于可回收對(duì)象,不可達(dá)對(duì)象變?yōu)榭苫厥諏?duì)象至少要經(jīng)過兩次標(biāo)記過程。兩次標(biāo)記后仍然是可回收對(duì)象,則將面臨回收。

2.4.2. 標(biāo)記清除算法(Mark-Sweep)
最基礎(chǔ)的垃圾回收算法,分為兩個(gè)階段,標(biāo)注和清除。標(biāo)記階段標(biāo)記出所有需要回收的對(duì)象,清除階段回收被標(biāo)記的對(duì)象所占用的空間。如圖

Java——JVM篇——收藏系列來啦(二)
從圖中我們就可以發(fā)現(xiàn),該算法最大的問題是內(nèi)存碎片化嚴(yán)重,后續(xù)可能發(fā)生大對(duì)象不能找到可利用空間的問題。

2.4.3. 復(fù)制算法(copying)
為了解決 Mark-Sweep 算法內(nèi)存碎片化的缺陷而被提出的算法。按內(nèi)存容量將內(nèi)存劃分為等大小的兩塊。每次只使用其中一塊,當(dāng)這一塊內(nèi)存滿后將尚存活的對(duì)象復(fù)制到另一塊上去,把已使用的內(nèi)存清掉,如圖

Java——JVM篇——收藏系列來啦(二)
這種算法雖然實(shí)現(xiàn)簡(jiǎn)單,內(nèi)存效率高,不易產(chǎn)生碎片,但是最大的問題是可用內(nèi)存被壓縮到了原本的一半。且存活對(duì)象增多的話,Copying 算法的效率會(huì)大大降低。

2.4.4. 標(biāo)記整理算法(Mark-Compact)
結(jié)合了以上兩個(gè)算法,為了避免缺陷而提出。標(biāo)記階段和 Mark-Sweep 算法相同,標(biāo)記后不是清理對(duì)象,而是將存活對(duì)象移向內(nèi)存的一端。然后清除端邊界外的對(duì)象。如圖:

Java——JVM篇——收藏系列來啦(二)
2.4.5. 分代收集算法
分代收集法是目前大部分 JVM 所采用的方法,其核心思想是根據(jù)對(duì)象存活的不同生命周期將內(nèi)存劃分為不同的域,一般情況下將 GC 堆劃分為老生代(Tenured/Old Generation)和新生代(Young Generation)。老生代的特點(diǎn)是每次垃圾回收時(shí)只有少量對(duì)象需要被回收,新生代的特點(diǎn)是每次垃圾回收時(shí)都有大量垃圾需要被回收,因此可以根據(jù)不同區(qū)域選擇不同的算法。

2.4.5.1. 新生代與復(fù)制算法
目前大部分 JVM 的 GC 對(duì)于新生代都采取 Copying 算法,因?yàn)樾律忻看卫厥斩家厥沾蟛糠謱?duì)象,即要復(fù)制的操作比較少,但通常并不是按照 1:1 來劃分新生代。一般將新生代劃分為一塊較大的 Eden 空間和兩個(gè)較小的 Survivor 空間(From Space, To Space),每次使用Eden 空間和其中的一塊 Survivor 空間,當(dāng)進(jìn)行回收時(shí),將該兩塊空間中還存活的對(duì)象復(fù)制到另一塊 Survivor 空間中。

Java——JVM篇——收藏系列來啦(二)
2.4.5.2. 老年代與標(biāo)記復(fù)制算法
而老年代因?yàn)槊看沃换厥丈倭繉?duì)象,因而采用 Mark-Compact 算法。

  1. JAVA 虛擬機(jī)提到過的處于方法區(qū)的永生代(Permanet Generation),它用來存儲(chǔ) class 類,常量,方法描述等。對(duì)永生代的回收主要包括廢棄常量和無用的類。

  2. 對(duì)象的內(nèi)存分配主要在新生代的 Eden Space 和 Survivor Space 的 From Space(Survivor 目前存放對(duì)象的那一塊),少數(shù)情況會(huì)直接分配到老生代。

  3. 當(dāng)新生代的 Eden Space 和 From Space 空間不足時(shí)就會(huì)發(fā)生一次 GC,進(jìn)行 GC 后,Eden Space 和 From Space 區(qū)的存活對(duì)象會(huì)被挪到 To Space,然后將 Eden Space 和 From Space 進(jìn)行清理。

  4. 如果 To Space 無法足夠存儲(chǔ)某個(gè)對(duì)象,則將這個(gè)對(duì)象存儲(chǔ)到老生代。

  5. 在進(jìn)行 GC 后,使用的便是 Eden Space 和 To Space 了,如此反復(fù)循環(huán)。

  6. 當(dāng)對(duì)象在 Survivor 區(qū)躲過一次 GC 后,其年齡就會(huì)+1。默認(rèn)情況下年齡到達(dá) 15 的對(duì)象會(huì)被移到老生代中。

2.5.JAVA 四中引用類型
2.5.1. 強(qiáng)引用
在 Java 中最常見的就是強(qiáng)引用,把一個(gè)對(duì)象賦給一個(gè)引用變量,這個(gè)引用變量就是一個(gè)強(qiáng)引用。當(dāng)一個(gè)對(duì)象被強(qiáng)引用變量引用時(shí),它處于可達(dá)狀態(tài),它是不可能被垃圾回收機(jī)制回收的,即使該對(duì)象以后永遠(yuǎn)都不會(huì)被用到 JVM 也不會(huì)回收。因此強(qiáng)引用是造成 Java 內(nèi)存泄漏的主要原因之一。

2.5.2. 軟引用
軟引用需要用 SoftReference 類來實(shí)現(xiàn),對(duì)于只有軟引用的對(duì)象來說,當(dāng)系統(tǒng)內(nèi)存足夠時(shí)它不會(huì)被回收,當(dāng)系統(tǒng)內(nèi)存空間不足時(shí)它會(huì)被回收。軟引用通常用在對(duì)內(nèi)存敏感的程序中。

2.5.3. 弱引用
弱引用需要用 WeakReference 類來實(shí)現(xiàn),它比軟引用的生存期更短,對(duì)于只有弱引用的對(duì)象來說,只要垃圾回收機(jī)制一運(yùn)行,不管 JVM 的內(nèi)存空間是否足夠,總會(huì)回收該對(duì)象占用的內(nèi)存。

2.5.4. 虛引用
虛引用需要 PhantomReference 類來實(shí)現(xiàn),它不能單獨(dú)使用,必須和引用隊(duì)列聯(lián)合使用。虛引用的主要作用是跟蹤對(duì)象被垃圾回收的狀態(tài)。

2.6.GC 分代收集算法 VS 分區(qū)收集算法
2.6.1. 分代收集算法
當(dāng)前主流 VM 垃圾收集都采用”分代收集”(Generational Collection)算法, 這種算法會(huì)根據(jù)對(duì)象存活周期的不同將內(nèi)存劃分為幾塊, 如 JVM 中的 新生代、老年代、永久代,這樣就可以根據(jù)各年代特點(diǎn)分別采用最適當(dāng)?shù)?GC 算法

2.6.1.1. 在新生代-復(fù)制算法
每次垃圾收集都能發(fā)現(xiàn)大批對(duì)象已死, 只有少量存活. 因此選用復(fù)制算法, 只需要付出少量存活對(duì)象的復(fù)制成本就可以完成收集.

2.6.1.2. 在老年代-標(biāo)記整理算法
因?yàn)閷?duì)象存活率高、沒有額外空間對(duì)它進(jìn)行分配擔(dān)保, 就必須采用“標(biāo)記—清理”或“標(biāo)記—整理”算法來進(jìn)行回收, 不必進(jìn)行內(nèi)存復(fù)制, 且直接騰出空閑內(nèi)存

2.6.2. 分區(qū)收集算法
分區(qū)算法則將整個(gè)堆空間劃分為連續(xù)的不同小區(qū)間, 每個(gè)小區(qū)間獨(dú)立使用, 獨(dú)立回收. 這樣做的好處是可以控制一次回收多少個(gè)小區(qū)間 , 根據(jù)目標(biāo)停頓時(shí)間, 每次合理地回收若干個(gè)小區(qū)間(而不是整個(gè)堆), 從而減少一次 GC 所產(chǎn)生的停頓

提前一飽眼福,附完整 JVM pdf文檔和最新學(xué)習(xí)視頻
VX獲取:13272413561

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI