溫馨提示×

溫馨提示×

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

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

jvm垃圾回收算法實例分析

發(fā)布時間:2022-07-19 09:44:51 來源:億速云 閱讀:198 作者:iii 欄目:開發(fā)技術(shù)

本篇內(nèi)容主要講解“jvm垃圾回收算法實例分析”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學(xué)習(xí)“jvm垃圾回收算法實例分析”吧!

    前言

    相比C語言,JVM虛擬機一個優(yōu)勢體現(xiàn)在對對象的垃圾回收上,JVM有一套完整的垃圾回收算法,可以對程序運行時產(chǎn)生的垃圾對象進行及時的回收,以便釋放JVM相應(yīng)區(qū)域的內(nèi)存空間,確保程序穩(wěn)定高效的運行,但在真正了解垃圾回收算法之前,有必要對JVM的對象的引用做一個簡單的鋪墊

    JVM對象可達性分析算法 Java虛擬機中的垃圾回收器采用可達性分析來探索所有存活的對象掃描堆中的對象,看是否能夠沿著GC Root對象為起點的引用鏈找到該對象,找不到表示可以被回收

    想象一下,對象在什么情況下會被認為是垃圾對象呢?

    當一個對象沒有被任何引用了,就認為對象無用了(如圖一)當一組對象沒有被任何引用了,可以認為這組對象無用了(如圖二)

    jvm垃圾回收算法實例分析

    jvm垃圾回收算法實例分析

    下面通過一段簡單的程序代碼,在不同的時刻導(dǎo)出dump日志,利用MAT分析工具來說明下這個問題

    public static void main(String[] args) throws Exception{
            List<Object> list1 = new ArrayList<>();
            list1.add("aaa");
            list1.add("bbb");
            System.out.println(1);
            System.in.read();
            list1 = null;
            System.out.println(1);
            System.in.read();
            System.out.println("end");
        }

    jvm垃圾回收算法實例分析

    運行程序,利用下面的命令導(dǎo)出兩個時刻的dump文件

    map -dump:format=b,live,file=a.dump 17356

    jvm垃圾回收算法實例分析

    分析第一個文件,在第一個時刻,此時由于list1集合中放了2個元素,因此該對象存在引用關(guān)系

    jvm垃圾回收算法實例分析

    再分析第二個文件,在第二個時刻,此時由于list1置為null,因此該對象沒有被引用的地方了,在gc root中找不到list1對象了

    jvm垃圾回收算法實例分析

    通過上面簡單的案例演示和說明,我們再次明確,對象被標為垃圾的前提是該對象從GC Root出發(fā)進行搜索時,找不到對該對象的引用,即為不可達對象

    幾種常用的垃圾回收算法

    1、引用計數(shù)法

    引用計數(shù)法在JVM的早期版本中有用到,引用計數(shù)是指采用計數(shù)器說明引用對象的個數(shù),即為某個對象設(shè)置一個引用對象數(shù)量的計數(shù)器,如果該對象被引用了,計數(shù)器的數(shù)量加1,否則減一,當計數(shù)器的數(shù)值為0的時候,垃圾回收器將該對象進行回收

    如下圖所示,某一時刻,對象A,B,C各自持有對對象P的引用,到另一時刻A,B,C不再對P對象進行引用了,計數(shù)器的值歸為0,此時垃圾回收器就對P對象進行垃圾回收

    jvm垃圾回收算法實例分析

    引用計數(shù)法在JVM垃圾回收算法中逐漸被廢棄,很簡單,如果存在對象之間的循環(huán)引用,則計數(shù)器的count值永遠不會清0,如此對象將會一直存在內(nèi)存中得不到釋放

    jvm垃圾回收算法實例分析

    2、根搜索算法

    根搜索算法是JVM的默認垃圾回收算法,也叫做“可達性分析算法”,即從GCRoot出發(fā),有引用的對象都是不可回收的,其他的可以進行標記后再回收

    如下圖所示,對某個線程棧來說,里面有局部變量,有靜態(tài)變量,常量池,或?qū)Ρ镜豱ative方法的調(diào)用,假設(shè)從某個棧幀的局部變量出發(fā),可認為是GCRoot的搜索起點,以此為起點,搜索整個引用鏈條上的所有引用對象,在這個鏈條上的對象認為是GCRoot可達的對象,否則將會被設(shè)為可回收對象被垃圾回收器回收

    jvm垃圾回收算法實例分析

    3、標記清除法(Mark-Sweep)

    標記清除算法主要經(jīng)歷標記和清除2個步驟,通過根搜索算法中的可達性分析之后,那些被標記為垃圾對象的內(nèi)存空間,通過該算法直接清除

    標記清除算法簡單粗暴,效率很高,因為不涉及到其他的步驟,但是從下面的圖示也可以看到,標記清除算法產(chǎn)生了不連續(xù)的內(nèi)存碎片(產(chǎn)生了內(nèi)存間隙)導(dǎo)致其內(nèi)存使用率比較低,如果程序中需要為某個大對象分配一大塊連續(xù)的內(nèi)存空間,則很難通過這種算法騰出這樣的內(nèi)存空間,因此該算法在JVM中并沒有使用到(作為一種垃圾回收算法的思想值得借鑒)

    jvm垃圾回收算法實例分析

    4、復(fù)制交換算法(Mark-Sweep)

    為解決Mark-Sweep算法的缺陷,Copying算法就被提了出來。它將可用內(nèi)存按容量劃分為大小相等的兩塊,每次只使用其中的一塊。當某一塊內(nèi)存用完了,就將還存活著的對象復(fù)制到另外一塊上面,然后再把已使用的內(nèi)存空間一次清理掉,這樣一來就不容易出現(xiàn)內(nèi)存碎片的問題

    在堆的年輕代進行GC的時候使用的就是復(fù)制算法,還記得新生代的區(qū)域劃分嗎?S0和S1兩個區(qū)域的內(nèi)存在實際使用時,總是其中一塊在使用,當達到了minor gc的條件時,就按照復(fù)制算法,將這塊空間中存活的對象轉(zhuǎn)移到另一塊,再清理當前這塊空間的垃圾對象

    總結(jié)來說,復(fù)制算法速度快,無內(nèi)存碎片,但缺點也比較明顯,就是浪費空間,在年輕代的 Minor Gc中使用

    jvm垃圾回收算法實例分析

    5、標記壓縮算法(Mark-Compact)

    為解決Copying算法的缺陷,充分利用內(nèi)存空間,提出了Mark-Compact算法。該算法標記階段和Mark-Sweep一樣,但是在完成標記之后,它不是直接清理可回收對象,而是將存活對象都向一端移動,然后清理掉端邊界以外的內(nèi)存

    標記壓縮算法整個垃圾回收的過程包括,標記 -> 壓縮 -> 整理 ->清除,通過下圖展示也不難發(fā)現(xiàn),標記壓縮進行垃圾回收之后,整個內(nèi)存區(qū)域的分布比較連續(xù)(無內(nèi)存碎片),但是很明顯這種算法的中間操作步驟相對上面兩種算法要復(fù)雜,因此在進行GC過程中比較耗時效率較低,在老年代的Full Gc時使用的就是標記壓縮算法

    jvm垃圾回收算法實例分析

    JVM 分代收集算法

    jvm垃圾回收算法實例分析

    在JVM的內(nèi)存結(jié)構(gòu)中,按照堆內(nèi)存的結(jié)構(gòu)劃分,大的方面可以分為年輕代和老年代,堆內(nèi)存是JVM中進行垃圾回收的主要區(qū)域

    但是各個區(qū)域在使用過程中的作用,對象生成規(guī)則,對象生命周期的不同又可以細分為各個邏輯上的結(jié)構(gòu),比如在新生代區(qū)域,可以劃分為 Eden區(qū)和Survivor區(qū),而Survivor再細分為from(s0)區(qū)和to(s1)區(qū),通過區(qū)域的劃分,各個區(qū)域的職責更加明確

    我們知道,新生代和老年代一個很大的區(qū)別在于,新生代是對象頻繁產(chǎn)生的區(qū)域,也是Minor Gc很頻繁的區(qū)域,而老年代中的對象大多則是比較穩(wěn)定的對象,從這個角度上說,各個區(qū)域在進行垃圾回收時策略自然不相同

    分代收集算法是目前大部分JVM的垃圾收集器采用的算法,新生代對象朝生夕死,生命周期短,內(nèi)存空間需要頻繁的進行清理以應(yīng)對快速而來的新對象,因此需要更高效的垃圾回收算法

    新生代

    目前大部分垃圾收集器對新生代都采取Copying算法,因為新生代中每次垃圾回收都要回收大部分對象,也就是說需要復(fù)制的操作次數(shù)較少,但實際中并不是按照1:1的比例來劃分新生代的空間的,一般來說是將新生代劃分為一塊較大的Eden空間和兩塊較小的Survivor空間(一般為8:1:1),每次使用Eden空間和其中的一塊Survivor空間,當進行回收時,將Eden和Survivor中還存活的對象復(fù)制到另一塊Survivor空間中,然后清理掉Eden和剛才使用過的Survivor空間

    老年代

    老年代內(nèi)存空間相對較大,可以存放更多的對象,通常情況下每次發(fā)生Full Gc的間隔時間也較長,而且在老年代中經(jīng)常需要存放一些大對象,需要連續(xù)的內(nèi)存空間,基于這些特點,在目前主流的JVM垃圾回收器中對于老年代采用壓縮算法

    到此,相信大家對“jvm垃圾回收算法實例分析”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

    向AI問一下細節(jié)

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

    jvm
    AI