jvm垃圾回收机制_干货|JVM垃圾回收机制
前言
不同于C++程序員必須自己完成內(nèi)存的分配、使用和釋放,JAVA語(yǔ)言提供了垃圾回收機(jī)制(GC,Garbage Collection),所以JAVA程序員僅需要負(fù)責(zé)分配和使用內(nèi)存即可,而釋放內(nèi)存則由GC負(fù)責(zé)。這樣程序員就從討厭的內(nèi)存管理的工作中脫身了。本文主要給大家介紹一下JVM如何查找需要被回收的對(duì)象實(shí)例與垃圾收集算法。
查找可回收對(duì)象
我們都知道垃圾回收機(jī)制是將內(nèi)存中不可能在被使用的的對(duì)象實(shí)例(可回收的對(duì)象實(shí)例)回收釋放其所占用的內(nèi)存,以供其他對(duì)象使用。JAVA的垃圾回收機(jī)制是對(duì)JAVA堆和方法區(qū)的內(nèi)存回收。那么CG是怎么知道該對(duì)象是否還會(huì)使用呢?
一、引用計(jì)數(shù)算法(Reference Counting)
引用計(jì)數(shù)算法簡(jiǎn)單的講就是給每個(gè)對(duì)象中添加一個(gè)引用計(jì)數(shù)器, 每當(dāng)有一個(gè)地方引用它時(shí),計(jì)數(shù)器值就加1:當(dāng)引用失效時(shí),計(jì)數(shù)器值就減1,當(dāng)對(duì)象的計(jì)數(shù)器為0就表示該對(duì)象已“死”,可以被回收了。雖然這種算法實(shí)現(xiàn)簡(jiǎn)單,判定效率也高。但是大部分JAVA虛擬機(jī)卻沒(méi)有使用此算法,因?yàn)檫@個(gè)算法很難解決對(duì)象之間互相循環(huán)引用的問(wèn)題。
二、可達(dá)性分析算法(Reachability Analysis)
可達(dá)性分析算法是通過(guò)被稱(chēng)為 “GC Roots" 的對(duì)象作為起始點(diǎn), 從這些節(jié)點(diǎn)開(kāi)始向下搜索,搜索所走過(guò)的路徑稱(chēng)為引用鏈(Reference Chain),當(dāng)一個(gè)對(duì)象到GC Roots沒(méi)有任何引用鏈相連,就是從GC Roots到這個(gè)對(duì)象不可達(dá)時(shí),則證明此對(duì)象是不可用的。如圖1.1。對(duì)象 2、對(duì)象 4、對(duì)象 6不可到達(dá)GC Roots所以會(huì)被回收。
圖1.1垃圾收集算法
通過(guò)上文我們知道了JVM如何查詢(xún)需要被回收的對(duì)象實(shí)例,那么JVM是通過(guò)什么方法把對(duì)象收回的呢?不同虛擬機(jī)回收內(nèi)存的方法各不相同,主流的方法有標(biāo)記-清除算法、復(fù)制算法、標(biāo)記-整理算法和分代收集算法。
一、標(biāo)記-清除算法(Mark-Sweep)
標(biāo)記-清除算法分為“標(biāo)記”和“清除”兩個(gè)階段:首先標(biāo)記出所有需要可收的對(duì)象,在標(biāo)記完成后統(tǒng)一回收所有被標(biāo)記的對(duì)象。如上文所介紹,標(biāo)記過(guò)程其實(shí)就是找出不可能在被使用的對(duì)象實(shí)例。如圖1.2首先標(biāo)記出需要被回收的對(duì)象,然后將這些對(duì)象回收,回收后的狀態(tài)如圖1.3。
回收前狀態(tài) 圖1.2回收后狀態(tài) 圖1.3標(biāo)記-清除算法主要有兩個(gè)不足:一個(gè)是效率問(wèn)題, 標(biāo)記和清除兩個(gè)過(guò)程的效率都不高;另一個(gè)是空間問(wèn)題,標(biāo)記清除之后會(huì)產(chǎn)生大量不連續(xù)的內(nèi)存碎片,空間碎片太多可能會(huì)導(dǎo)致以后在程序運(yùn)行過(guò)程中需要分配較大對(duì)象時(shí),無(wú)法找到足夠的連續(xù)內(nèi)存而不得不提前觸發(fā)另一次垃圾收集動(dòng)作。
二、復(fù)制算法(Copying)
復(fù)制算法將可用內(nèi)存容量劃分為大小相等的兩塊,每次只使用其中的一塊。當(dāng)這一塊的內(nèi)存用完了,就將還存活著的對(duì)象復(fù)制到另外一塊上面,然后再把已使用過(guò)的這一塊的內(nèi)存空間全部清理掉。這樣使得每次GC是對(duì)整半個(gè)內(nèi)存區(qū)域進(jìn)行回收,內(nèi)存分配時(shí)也就不用考慮內(nèi)存碎片等問(wèn)題,只要移動(dòng)堆指針,按順序分配內(nèi)存即可。這種方式實(shí)現(xiàn)簡(jiǎn)單,運(yùn)行高效。但是這種算法的代價(jià)是將內(nèi)存縮小為原來(lái)的一半,未免太高了一點(diǎn)。復(fù)制算法的執(zhí)行過(guò)程如圖1.4與圖1.5所示。
回收前狀態(tài) 圖1.4回收后狀態(tài) 圖1.5三、標(biāo)記-整理算法(Mark-Compact)
標(biāo)記-整理算法,標(biāo)記過(guò)程與標(biāo)記-清除算法一樣,但后續(xù)步驟不是直接對(duì)可回收對(duì)象進(jìn)行清理,而是讓所有存活的對(duì)象都向一端移動(dòng), 然后直接清理掉端邊界以外的內(nèi)存,“標(biāo)記-整理”算法的過(guò)程如圖1.6與圖1.7所示。
回收前狀態(tài) 圖1.6回收后狀態(tài) 圖1.7四、分代收集算法(Generational Colllection)
當(dāng)前主流虛機(jī)的垃圾收集都采用“分代收集”,這種算法并沒(méi)有什么新的思想,只是根據(jù)對(duì)象存活周期的不同將內(nèi)存劃分為幾塊。一般是把JAVA堆分為新生代和老年代(新生代與老年代后續(xù)會(huì)有文章介紹),這樣就可以根據(jù)各個(gè)年代的特點(diǎn)采用最適當(dāng)?shù)氖占惴āT谛律?#xff0c;每次垃圾收集時(shí)都發(fā)現(xiàn)有大批對(duì)象死去,只有少量存活,那就選用復(fù)制算法,只需要付出少量存活對(duì)象的復(fù)制成本就可以完成收集。而老年代中因?yàn)閷?duì)象存活率高、所以使用“標(biāo)記-清除”或者“標(biāo)記-整理” 算法來(lái)進(jìn)行回收。
更多文章可關(guān)注微信公眾號(hào):IT雞窩
總結(jié)
以上是生活随笔為你收集整理的jvm垃圾回收机制_干货|JVM垃圾回收机制的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: python如何改变入参的值_从事数据分
- 下一篇: oracle 作业已存在,ORA-316