欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JVM垃圾回收機(jī)制之GC解讀

 更新時(shí)間:2025年05月04日 21:57:57   作者:棕豆兔&  
這篇文章主要介紹了JVM垃圾回收機(jī)制之GC,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

JVM的垃圾回收機(jī)制:GC,是Java提供的對(duì)于內(nèi)存自動(dòng)回收的機(jī)制。

在 Java 中,所有的對(duì)象都是要存在內(nèi)存中的(也可以說內(nèi)存中存儲(chǔ)的是一個(gè)個(gè)對(duì)象),因此將內(nèi)存回收,也可以叫做死亡對(duì)象的回收。GC回收的是“堆上的內(nèi)存”。

一、死亡對(duì)象的判斷算法

1.1 引用計(jì)數(shù)算法

思想:

給對(duì)象增加一個(gè)引用計(jì)數(shù)器,每當(dāng)有一個(gè)地方引用它時(shí),計(jì)數(shù)器就+1;當(dāng)引用失效時(shí),計(jì)數(shù)器就-1; 任何時(shí)刻計(jì)數(shù)器為0的對(duì)象就是不能再被使用的,即對(duì)象已"死"。

引用計(jì)數(shù)法實(shí)現(xiàn)簡單,判定效率也比較高,在大部分情況下都是一個(gè)不錯(cuò)的算法。比如Python語言就采用引用計(jì)數(shù)法進(jìn)行內(nèi)存管理。

在主流的JVM中沒有選用引用計(jì)數(shù)法來管理內(nèi)存,最主要的原因就是引用計(jì)數(shù)法無法解決對(duì)象的循環(huán)引用問題。

1.2 可達(dá)性分析算法

思想:

通過一系列稱為"GC Roots"的對(duì)象作為起始點(diǎn),從這些節(jié)點(diǎn)開始向下搜索,搜索走過的路徑稱之為"引用鏈",當(dāng)一個(gè)對(duì)象到 GC Roots 沒有任何的引用鏈相連時(shí) (從GC Roots到這個(gè)對(duì)象不可達(dá))時(shí),證明此對(duì)象是不可用的。如下:

對(duì)象 Object5 - Object7 之間雖然彼此還有關(guān)聯(lián),但是它們到 GC Roots 是不可達(dá)的,因此他們會(huì)被判定為可回收對(duì)象。

在Java語言中,可作為 GC Roots 的對(duì)象包含下面幾種:

  • 虛擬機(jī)棧(棧幀中的本地變量表)中引用的對(duì)象;
  • 方法區(qū)中類靜態(tài)屬性引用的對(duì)象;
  • 方法區(qū)中常量引用的對(duì)象;
  • 本地方法棧中 JNI(Native方法)引用的對(duì)象。

在 JDK1.2 時(shí),Java 對(duì)引用的概念做了擴(kuò)充,分為以下四種,這四種引用的強(qiáng)度依次遞減:

  • 強(qiáng)引用 : 強(qiáng)引用指的是在程序代碼之中普遍存在的,類似于"Object obj = new Object()"這類的引用,只要強(qiáng)引用還存在,垃圾回收器永遠(yuǎn)不會(huì)回收掉被引用的對(duì)象實(shí)例。
  • 軟引用 : 軟引用是用來描述一些還有用但是不是必須的對(duì)象。對(duì)于軟引用關(guān)聯(lián)著的對(duì)象,在系統(tǒng)將要發(fā)生內(nèi)存溢出之前,會(huì)把這些對(duì)象列入回收范圍之中進(jìn)行第二次回收。如果這次回收還是沒有足夠的內(nèi)存,才會(huì)拋出內(nèi)存溢出異常。在JDK1.2之后,提供了SoftReference類來實(shí)現(xiàn)軟引用。
  • 弱引用 : 弱引用也是用來描述非必需對(duì)象的。但是它的強(qiáng)度要弱于軟引用。被弱引用關(guān)聯(lián)的對(duì)象只能生存到下一次垃圾回收發(fā)生之前。當(dāng)垃圾回收器開始進(jìn)行工作時(shí),無論當(dāng)前內(nèi)容是否夠用,都會(huì)回收掉只被弱引用關(guān)聯(lián)的對(duì)象。在JDK1.2之后提供了WeakReference類來實(shí)現(xiàn)弱引用。
  • 虛引用 : 虛引用也被稱為幽靈引用或者幻影引用,它是最弱的一種引用關(guān)系。一個(gè)對(duì)象是否有虛引用的存在,完全不會(huì)對(duì)其生存時(shí)間構(gòu)成影響,也無法通過虛引用來取得一個(gè)對(duì)象實(shí)例。為一個(gè)對(duì)象設(shè)置虛引用的唯一目的就是能在這個(gè)對(duì)象被收集器回收時(shí)收到一個(gè)系統(tǒng)通知。在JDK1.2之后,提供了PhantomReference類來實(shí)現(xiàn)虛引用。

二、垃圾回收算法

2.1 標(biāo)記-清除算法

"標(biāo)記-清除"算法是最基礎(chǔ)的收集算法。算法分為"標(biāo)記"和"清除"兩個(gè)階段 : 首先標(biāo)記出所有需要回收的對(duì)象,在標(biāo)記完成后統(tǒng)一回收所有被標(biāo)記的對(duì)象。后續(xù)的收集算法都是基于這種思路并對(duì)其不足加以改進(jìn)而已。

"標(biāo)記-清除"算法的不足主要有兩個(gè) :
  • 效率問題 : 標(biāo)記和清除這兩個(gè)過程的效率都不高。
  • 空間問題 : 標(biāo)記清除后會(huì)產(chǎn)生大量不連續(xù)的內(nèi)存碎片,空間碎片太多可能會(huì)導(dǎo)致以后在程序運(yùn)行中需要分配較大對(duì)象時(shí),無法找到足夠連續(xù)內(nèi)存而不得不提前觸發(fā)另一次垃圾收集。

2.2 復(fù)制算法

復(fù)制"算法是為了解決"標(biāo)記-清理"的效率問題。

它將可用內(nèi)存按容量劃分為大小相等的兩塊,每次只使用其中的一塊。當(dāng)這塊內(nèi)存需要進(jìn)行垃圾回收時(shí),會(huì)將此區(qū)域還存活著的對(duì)象復(fù)制到另一塊上面,然后再把已經(jīng)使用過的內(nèi)存區(qū)域一次清理掉。這樣做的好處是每次都是對(duì)整個(gè)半?yún)^(qū)進(jìn)行內(nèi)存回收,內(nèi)存分配時(shí)也就不需要考慮內(nèi)存碎片等復(fù)雜情況,只需要移動(dòng)堆頂指針,按順序分配即可。

此算法實(shí)現(xiàn)簡單,運(yùn)行高效。算法的執(zhí)行流程如下圖 :

2.3 標(biāo)記-整理算法

復(fù)制收集算法在對(duì)象存活率較高時(shí)會(huì)進(jìn)行比較多的復(fù)制操作,效率會(huì)變低。因此在老年代一般不能使用復(fù)制算法。 針對(duì)老年代的特點(diǎn),提出了一種稱之為"標(biāo)記-整理算法"。標(biāo)記過程仍與"標(biāo)記-清除"過程?致,但后續(xù)步驟不是直接對(duì)可回收對(duì)象進(jìn)行清理,而是讓所有存活對(duì)象都向一端移動(dòng),然后直接清理掉端邊界以外的內(nèi)存。

流程圖如下:

2.4 分代算法

分代算法和上面 3 種算法不同,分代算法是通過區(qū)域劃分,實(shí)現(xiàn)不同區(qū)域和不同的垃圾回收策略,從而實(shí)現(xiàn)更好的垃圾回收。

當(dāng)前 JVM 垃圾收集都采用的是"分代收集(Generational Collection)"算法,這個(gè)算法并沒有新思想,只是根據(jù)對(duì)象存活周期的不同將內(nèi)存劃分為幾塊。

一般是把Java堆分為新生代和老年代。在新生代中,每次垃圾回收都有大批對(duì)象死去,只有少量存活,因此我們采用復(fù)制算法;而老年代中對(duì)象存活率高、沒有額外空間對(duì)它進(jìn)行分配擔(dān)保,就必須采用"標(biāo)記-清理"或者"標(biāo)記-整理"算法。

哪些對(duì)象會(huì)進(jìn)入新生代?哪些對(duì)象會(huì)進(jìn)入老年代?

  • 新生代:一般創(chuàng)建的對(duì)象都會(huì)進(jìn)入新生代;
  • 老年代:大對(duì)象和經(jīng)歷了 N 次(一般情況默認(rèn)是 15 次)垃圾回收依然存活下來的對(duì)象會(huì)從新生代移動(dòng)到老年代。

面試題 : 請(qǐng)問了解Minor GC和Full GC么,這兩種GC有什么不一樣嗎?

  • Minor GC 又稱為新生代GC : 指的是發(fā)生在新生代的垃圾收集。因?yàn)镴ava對(duì)象大多都具備朝生夕滅的特性,因此Minor GC(采用復(fù)制算法)非常頻繁,一般回收速度也比較快。
  • Full GC 又稱為老年代GC 或者 Major GC : 指發(fā)生在老年代的垃圾收集。出現(xiàn)了Major GC,經(jīng)常會(huì)伴隨至少一次的Minor GC (并非絕對(duì),在Parallel Scavenge收集器中就有直接進(jìn)行Full GC的策略選擇過程)。Major GC的速度一般會(huì)比Minor GC慢10倍以上。

三、垃圾收集器

收集算法是內(nèi)存回收的方法論,垃圾收集器是內(nèi)存回收的具體實(shí)現(xiàn)。

垃圾收集器的作用:垃圾收集器是為了保證程序能夠正常、持久運(yùn)行的一種技術(shù),它是將程序中不用的死亡對(duì)象也就是垃圾對(duì)象進(jìn)行清除,從而保證了新對(duì)象能夠正常申請(qǐng)到內(nèi)存空間。

以下這些收集器是 HotSpot 虛擬機(jī)隨著不同版本推出的重要的垃圾收集器:

上圖展示了7種作用于不同分代的收集器,如果兩個(gè)收集器之間存在連線,就說明他們之間可以搭配使用。所處的區(qū)域,表示它是屬于新生代收集器還是老年代收集器。

  • 并行(Parallel) : 指多條垃圾收集線程并行工作,用戶線程仍處于等待狀態(tài)。
  • 并發(fā)(Concurrent) : 指用戶線程與垃圾收集線程同時(shí)執(zhí)行 (不一定并行,可能會(huì)交替執(zhí)行),用戶程序繼續(xù)運(yùn)行,而垃圾收集程序在另外一個(gè)CPU上。
  • 吞吐量:就是CPU用于運(yùn)行用戶代碼的時(shí)間與CPU總消耗時(shí)間的比值。
  • 吞吐量 = 運(yùn)行用戶代碼時(shí)間/(運(yùn)行用戶代碼時(shí)間 + 垃圾收集時(shí)間)

例如:虛擬機(jī)總共運(yùn)行了100分鐘,其中垃圾收集花掉1分鐘,那吞吐量就是99%。

3.1 CMS收集器(老年代收集器,并發(fā)GC)

特性:

CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時(shí)間為目標(biāo)的收集器。目前很大一部分的Java應(yīng)用集中在互聯(lián)網(wǎng)站或者B/S系統(tǒng)的服務(wù)端上,這類應(yīng)用尤其重視服務(wù)的響應(yīng)速度,希望系統(tǒng)停頓時(shí)間最短,以給用戶帶來較好的體驗(yàn)。CMS收集器就非常符合這類應(yīng)用的需求。

CMS收集器是基于“標(biāo)記—清除”算法實(shí)現(xiàn)的,它的整個(gè)過程分為4個(gè)步驟:

  • 1. 初始標(biāo)記(CMS initial mark):初始標(biāo)記僅僅只是標(biāo)記一下GC Roots能直接關(guān)聯(lián)到的對(duì)象,速度很快,需要“Stop The World”。
  • 2. 并發(fā)標(biāo)記(CMS concurrent mark):并發(fā)標(biāo)記階段就是進(jìn)行GC Roots Tracing的過程。
  • 3. 重新標(biāo)記(CMS remark):重新標(biāo)記階段是為了修正并發(fā)標(biāo)記期間因用戶程序繼續(xù)運(yùn)作而導(dǎo)致標(biāo)記產(chǎn)生變動(dòng)的那一部分對(duì)象的標(biāo)記記錄,這個(gè)階段的停頓時(shí)間一般會(huì)比初始標(biāo)記階段稍長一些,但遠(yuǎn)比并發(fā)標(biāo)記的時(shí)間短,仍然需要“Stop The World”。
  • 4. 并發(fā)清除(CMS concurrent sweep):并發(fā)清除階段會(huì)清除對(duì)象。 由于整個(gè)過程中耗時(shí)最長的并發(fā)標(biāo)記和并發(fā)清除過程收集器線程都可以與用戶線程一起工作,所以,從總體上來說,CMS收集器的內(nèi)存回收過程是與用戶線程一起并發(fā)執(zhí)行的。

優(yōu)點(diǎn):

  • CMS是一款優(yōu)秀的收集器,它的主要優(yōu)點(diǎn)在名字上已經(jīng)體現(xiàn)出來了:并發(fā)收集、低停頓。

缺點(diǎn):

  • CMS收集器對(duì)CPU資源非常敏感;
  • CMS收集器無法處理浮動(dòng)垃圾;
  • CMS收集器會(huì)產(chǎn)生大量空間碎片。

3.2 G1收集器(唯一一款全區(qū)域的垃圾回收器)

G1(Garbage First)垃圾回收器是用在heap memory很大的情況下,把heap劃分為很多很多的 region塊,然后并行的對(duì)其進(jìn)行垃圾回收。

G1垃圾回收器在清除實(shí)例所占用的內(nèi)存空間后,還會(huì)做內(nèi)存壓縮。

年輕代垃圾收集 :

在G1垃圾收集器中,年輕代的垃圾回收過程使用復(fù)制算法。把Eden區(qū)和Survivor區(qū)的對(duì)象復(fù)制到新的Survivor區(qū)域。 如下圖:

老年代垃收集:

  • 對(duì)于老年代上的垃圾收集,G1垃圾收集器也分為4個(gè)階段,基本跟CMS垃圾收集器一樣,但略有不同:
  • 初始標(biāo)記(Initial Mark)階段:同CMS垃圾收集器的Initial Mark階段一樣,G1也需要暫停應(yīng)用程序的執(zhí)行,它會(huì)標(biāo)記從根對(duì)象出發(fā),在根對(duì)象的第一層孩子節(jié)點(diǎn)中標(biāo)記所有可達(dá)的對(duì)象。但是G1的垃圾收集器的Initial Mark階段是跟minor gc一同發(fā)生的。也就是說,在G1中,你不用像在CMS那樣,單獨(dú)暫停應(yīng)用程序的執(zhí)行來運(yùn)行Initial Mark階段,而是在G1觸發(fā)minor gc的時(shí)候一并將年老代上的Initial Mark給做了。
  • 并發(fā)標(biāo)記(Concurrent Mark)階段:在這個(gè)階段G1做的事情跟CMS一樣。但G1同時(shí)還多做了一件事情,就是如果在Concurrent Mark階段中,發(fā)現(xiàn)哪些Tenured region中對(duì)象的存活率很小或者基本沒有對(duì)象存活,那么G1就會(huì)在這個(gè)階段將其回收掉,而不用等到后面的clean up階段。這也是Garbage First名字的由來。同時(shí),在該階段,G1會(huì)計(jì)算每個(gè) region的對(duì)象存活率,方便后面的clean up階段使用 。
  • 最終標(biāo)記(CMS中的Remark階段):在這個(gè)階段G1做的事情跟CMS一樣, 但是采用的算法不同,G1采用一種叫做SATB(snapshot-at-the-begining)的算法能夠在Remark階段更快的標(biāo)記可達(dá)對(duì)象。
  • 篩選回收(Clean up/Copy)階段:在G1中,沒有CMS中對(duì)應(yīng)的Sweep階段。相反,它有一個(gè)Clean up/Copy階段,在這個(gè)階段中,G1會(huì)挑選出那些對(duì)象存活率低的region進(jìn)行回收,這個(gè)階段也是和minor gc一同發(fā)生的,如下圖所示:

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • SpringBoot集成Aviator實(shí)現(xiàn)參數(shù)校驗(yàn)的代碼工程

    SpringBoot集成Aviator實(shí)現(xiàn)參數(shù)校驗(yàn)的代碼工程

    Aviator是一個(gè)高性能、輕量級(jí)的java語言實(shí)現(xiàn)的表達(dá)式求值引擎,主要用于各種表達(dá)式的動(dòng)態(tài)求值,本文給大家詳細(xì)介紹了SpringBoot集成Aviator實(shí)現(xiàn)參數(shù)校驗(yàn)的方法,并通過代碼示例講解的非常詳細(xì),需要的朋友可以參考下
    2024-11-11
  • Netty分布式解碼器讀取數(shù)據(jù)不完整的邏輯剖析

    Netty分布式解碼器讀取數(shù)據(jù)不完整的邏輯剖析

    這篇文章主要為大家介紹了Netty分布式解碼器讀取數(shù)據(jù)不完整的邏輯剖析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-03-03
  • Java Netty核心模塊超詳細(xì)梳理

    Java Netty核心模塊超詳細(xì)梳理

    Netty是一個(gè)java開源項(xiàng)目,是一個(gè)異步的、基于事件驅(qū)動(dòng)的網(wǎng)絡(luò)應(yīng)用框架,用以開發(fā)高性能、高可用的網(wǎng)絡(luò)io程序,這篇文章主要介紹了Netty核心模塊
    2022-11-11
  • 比較排序之快速排序(實(shí)例代碼)

    比較排序之快速排序(實(shí)例代碼)

    下面小編就為大家?guī)硪黄容^排序之快速排序(實(shí)例代碼)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-06-06
  • postman測(cè)試傳入List<String>參數(shù)方式

    postman測(cè)試傳入List<String>參數(shù)方式

    這篇文章主要介紹了postman測(cè)試傳入List<String>參數(shù)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • IDEA創(chuàng)建web項(xiàng)目出現(xiàn)404錯(cuò)誤解決方法

    IDEA創(chuàng)建web項(xiàng)目出現(xiàn)404錯(cuò)誤解決方法

    今天先來搭建一個(gè)web工程,工程搭建好運(yùn)行時(shí)發(fā)現(xiàn)404,本文主要介紹了IDEA創(chuàng)建web項(xiàng)目出現(xiàn)404錯(cuò)誤解決方法,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-09-09
  • Java獲取當(dāng)前時(shí)間方法總結(jié)

    Java獲取當(dāng)前時(shí)間方法總結(jié)

    本篇文章給大家整理了關(guān)于Java獲取當(dāng)前時(shí)間方法,以及相關(guān)代碼分享,有需要的朋友測(cè)試參考下吧。
    2018-02-02
  • Spring Boot 整合mybatis 與 swagger2

    Spring Boot 整合mybatis 與 swagger2

    之前使用springMVC+spring+mybatis,總是被一些繁瑣的xml配置,還經(jīng)常出錯(cuò),下面把以前的一些ssm項(xiàng)目改成了spring boot + mybatis,相對(duì)于來說優(yōu)點(diǎn)太明顯了,具體內(nèi)容詳情大家通過本文學(xué)習(xí)吧
    2017-08-08
  • JavaWeb實(shí)現(xiàn)文件上傳下載功能實(shí)例詳解

    JavaWeb實(shí)現(xiàn)文件上傳下載功能實(shí)例詳解

    這篇文章主要介紹了JavaWeb中的文件上傳和下載功能的實(shí)現(xiàn),在開發(fā)中,文件上傳和下載功能是非常常用的功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-11-11
  • Spring中@Transactional注解的使用詳解

    Spring中@Transactional注解的使用詳解

    @Transactional注解是Spring提供的一種聲明式事務(wù)管理方式,這篇文章主要為大家詳細(xì)介紹了@Transactional注解的原理分析及使用,需要的可以參考一下
    2023-05-05

最新評(píng)論