日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

垃圾回收算法与垃圾回收器

發(fā)布時間:2023/12/18 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 垃圾回收算法与垃圾回收器 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

JavaC++等語言最大的技術(shù)區(qū)別:自動化的垃圾回收機制(GC

為什么要了解GC和內(nèi)存分配策略

1、面試需要

2GC對應(yīng)用的性能是有影響的;

3、寫代碼有好處

棧:棧中的生命周期是跟隨線程,所以一般不需要關(guān)注

堆:堆中的對象是垃圾回收的重點

方法區(qū)/元空間:這一塊也會發(fā)生垃圾回收,不過這塊的效率比較低,一般不是我們關(guān)注的重點

判斷對象的存活

引用計數(shù)法

給對象添加一個引用計數(shù)器,當(dāng)對象增加一個引用時計數(shù)器加 1,引用失效時計數(shù)器減 1。引用計數(shù)為 0 的對象可被回收。(Python在用,但主流虛擬機沒有使用)

優(yōu)點:快,方便,實現(xiàn)簡單。

缺陷:對象相互引用時(A.instance=B同時B.instance=A),很難判斷對象是否該回收。

可達(dá)性分析(Java中使用)

(面試時重要的知識點,牢記)

來判定對象是否存活的。這個算法的基本思路就是通過一系列的稱為GC Roots”的對象作為起始點,從這些節(jié)點開始向下搜索,搜索所走過的路徑稱為引用鏈(Reference Chain),當(dāng)一個對象到GC Roots沒有任何引用鏈相連時,則證明此對象是不可用的。

作為GC Roots的對象包括下面幾種:

當(dāng)前虛擬機棧中局部變量表中的引用的對象

當(dāng)前本地方法棧中局部變量表中的引用的對象

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

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

請忘記 finalize

finalize可以完成對象的拯救,但是JVM不保證一定能執(zhí)行,所以請忘記這個“坑”。

各種引用(Reference

傳統(tǒng)定義:Reference中存儲的數(shù)據(jù)代表的是另一塊內(nèi)存的起始地址。

強引用

一般的Object obj = new Object() ,就屬于強引用。

(如果有GCroots的強引用)垃圾回收器絕對不會回收它,當(dāng)內(nèi)存不足時寧愿拋出 OOM 錯誤,使得程序異常停止

軟引用 SoftReference

垃圾回收器在內(nèi)存充足的時候不會回收它,而在內(nèi)存不足時會回收它

軟引用非常適合于創(chuàng)建緩存。當(dāng)系統(tǒng)內(nèi)存不足的時候,緩存中的內(nèi)容是可以被釋放的。

一些有用但是并非必需,用軟引用關(guān)聯(lián)的對象,系統(tǒng)將要發(fā)生OOM之前,這些對象就會被回收。參見代碼:

VM參數(shù) -Xms10m ?-Xmx10m -XX:+PrintGC

?

運行結(jié)果

?

例如,一個程序用來處理用戶提供的圖片。如果將所有圖片讀入內(nèi)存,這樣雖然可以很快的打開圖片,但內(nèi)存空間使用巨大,一些使用較少的圖片浪費內(nèi)存空間,需要手動從內(nèi)存中移除。如果每次打開圖片都從磁盤文件中讀取到內(nèi)存再顯示出來,雖然內(nèi)存占用較少,但一些經(jīng)常使用的圖片每次打開都要訪問磁盤,代價巨大。這個時候就可以用軟引用構(gòu)建緩存。

弱引用 WeakReference

垃圾回收器在掃描到該對象時,無論內(nèi)存充足與否,都會回收該對象的內(nèi)存。

一些有用(程度比軟引用更低)但是并非必需,用弱引用關(guān)聯(lián)的對象,只能生存到下一次垃圾回收之前,GC發(fā)生時,不管內(nèi)存夠不夠,都會被回收。

參看代碼:

?

?

注意:軟引用 SoftReference和弱引用 WeakReference,可以用在內(nèi)存資源緊張的情況下以及創(chuàng)建不是很重要的數(shù)據(jù)緩存。當(dāng)系統(tǒng)內(nèi)存不足的時候,緩存中的內(nèi)容是可以被釋放的。

實際運用(WeakHashMapThreadLocal

虛引用 PhantomReference

幽靈引用,最弱,被垃圾回收的時候收到一個通知

如果一個對象只具有虛引用,那么它和沒有任何引用一樣,任何時候都可能被回收。

虛引用主要用來跟蹤對象被垃圾回收器回收的活動

GCGarbage Collection

案例Oom

-Xms ?堆區(qū)內(nèi)存初始內(nèi)存分配的大小

-Xmx ?堆區(qū)內(nèi)存可被分配的最大上限

-XX:+PrintGCDetails

打印GC詳情

-XX:+HeapDumpOnOutOfMemoryError

當(dāng)堆內(nèi)存空間溢出時輸出堆的內(nèi)存快照

新生代大小配置參數(shù)的優(yōu)先級:

中間 -Xmn ?限定大小

?

-XX:SurvivorRatio

2Survivor區(qū)和Eden區(qū)的比值

8 表示 兩個Survivor Eden = 28 ,每個Survivor1/10

可以修改為2

8 表示 兩個Survivor Eden = 22 ?,各占一半

GC overhead limit exceeded 超過98%的時間用來做GC并且回收了不到2%的堆內(nèi)存時會拋出此異常

1.垃圾回收會占據(jù)資源

2.回收效率過低也會有限制

為什么new出的對象不會被回收了,我們來看看GC是如何判斷對象的存活

?

?

Minor GC

特點: 發(fā)生在新生代上,發(fā)生的較頻繁,執(zhí)行速度較快

觸發(fā)條件: Eden區(qū)空間不足\空間分配擔(dān)保

Full GC

特點:主要發(fā)生在老年代上(新生代也會回收),較少發(fā)生,執(zhí)行速度較慢

觸發(fā)條件:

調(diào)用 System.gc()

老年代區(qū)域空間不足

空間分配擔(dān)保失敗

JDK 1.7 及以前的永久代(方法區(qū))空間不足

CMS GC處理浮動垃圾時,如果新生代空間不足,則采用空間分配擔(dān)保機制,如果老年代空間不足,則觸發(fā)Full GC

垃圾回收算法

復(fù)制算法(Copying

將可用內(nèi)存按容量劃分為大小相等的兩塊,每次只使用其中的一塊。當(dāng)這一塊的內(nèi)存用完了,就將還存活著的對象復(fù)制到另外一塊上面,然后再把已使用過的內(nèi)存空間一次清理掉。這樣使得每次都是對整個半?yún)^(qū)進(jìn)行內(nèi)存回收,內(nèi)存分配時也就不用考慮內(nèi)存碎片等復(fù)雜情況,只要按順序分配內(nèi)存即可,實現(xiàn)簡單,運行高效。只是這種算法的代價是將內(nèi)存縮小為了原來的一半。

注意:內(nèi)存移動是必須實打?qū)嵉囊苿?#xff08;復(fù)制),不能使用指針玩。

?

專門研究表明,新生代中的對象98%“朝生夕死”的,所以一般來說回收占據(jù)10%的空間夠用了,所以并不需要按照1:1的比例來劃分內(nèi)存空間,而是將內(nèi)存分為一塊較大的Eden空間和兩塊較小的Survivor空間,每次使用Eden和其中一塊Survivor[1]。當(dāng)回收時,將Eden和Survivor中還存活著的對象一次性地復(fù)制到另外一塊Survivor空間上,最后清理掉Eden和剛才用過的Survivor空間。

HotSpot虛擬機默認(rèn)Eden和Survivor的大小比例是8:1,也就是每次新生代中可用內(nèi)存空間為整個新生代容量的90%(80%+10%),只有10%的內(nèi)存會被“浪費”。

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

過程:

  • 首先標(biāo)記所有需要回收的對象
  • 統(tǒng)一回收被標(biāo)記的對象
  • 缺點:

    1.效率問題,標(biāo)記和清除效率都不高

    2.標(biāo)記清除之后會產(chǎn)生大量不連續(xù)的內(nèi)存碎片,空間碎片太多可能會導(dǎo)致以后在程序運行過程中需要分配較大對象時,無法找到足夠的連續(xù)內(nèi)存而不得不提前觸發(fā)另一次垃圾收集動作。

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

    首先標(biāo)記出所有需要回收的對象,在標(biāo)記完成后,后續(xù)步驟不是直接對可回收對象進(jìn)行清理,而是讓所有存活的對象都向一端移動,然后直接清理掉端邊界以外的內(nèi)存。

    垃圾回收器

    分代收集

    根據(jù)各個年代的特點選取不同的垃圾收集算法

    新生代使用復(fù)制算法

    老年代使用標(biāo)記-整理或者標(biāo)記-清除算法

    jps -v顯示當(dāng)前使用的垃圾回收器

    ?

    在新生代中,每次垃圾收集時都發(fā)現(xiàn)有大批對象死去,只有少量存活,那就選用復(fù)制算法,只需要付出少量存活對象的復(fù)制成本就可以完成收集。

    而老年代中因為對象存活率高、沒有額外空間對它進(jìn)行分配擔(dān)保,就必須使用“標(biāo)記—清理”或者“標(biāo)記—整理”算法來進(jìn)行回收。

    請記住下圖的垃圾收集器和之間的連線關(guān)系。

    ?

    并行:垃圾收集的多線程的同時進(jìn)行。

    并發(fā):垃圾收集的多線程和應(yīng)用的多線程同時進(jìn)行。

    ?

    注:吞吐量=運行用戶代碼時間/(運行用戶代碼時間+ 垃圾收集時間)

    垃圾收集時間= 垃圾回收頻率 * 單次垃圾回收時間

    各種垃圾回收器

    Serial/Serial Old

    最古老的,單線程,獨占式,成熟,適合單CPU ?服務(wù)器

    -XX:+UseSerialGC 新生代和老年代都用串行收集器

    -XX:+UseParNewGC 新生代使用ParNew,老年代使用Serial Old

    -XX:+UseParallelGC 新生代使用ParallerGC,老年代使用Serial Old

    ?

    ParNew

    Serial基本沒區(qū)別,唯一的區(qū)別:多線程,多CPU的,停頓時間比Serial

    -XX:+UseParNewGC 新生代使用ParNew,老年代使用Serial Old

    除了性能原因外,主要是因為除了 Serial 收集器,只有它能與 CMS 收集器配合工作。

    ?

    Parallel ScavengeParallerGC/Parallel Old

    關(guān)注吞吐量的垃圾收集器,高吞吐量則可以高效率地利用CPU時間,盡快完成程序的運算任務(wù),主要適合在后臺運算而不需要太多交互的任務(wù)。

    所謂吞吐量就是CPU用于運行用戶代碼的時間與CPU總消耗時間的比值,即吞吐量=運行用戶代碼時間/(運行用戶代碼時間+垃圾收集時間),虛擬機總共運行了100分鐘,其中垃圾收集花掉1分鐘,那吞吐量就是99%。

    ?

    Concurrent Mark Sweep CMS

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

    -XX:+UseConcMarkSweepGC ,一般新生代使用ParNew,老年代的用CMS

    從名字(包含“Mark Sweep”)上就可以看出,CMS收集器是基于“標(biāo)記—清除”算法實現(xiàn)的,它的運作過程相對于前面幾種收集器來說更復(fù)雜一些,

    垃圾回收過程

    整個過程分為4個步驟,包括:

    l?初始標(biāo)記:僅僅只是標(biāo)記一下 GC Roots 能直接關(guān)聯(lián)到的對象,速度很快,需要停頓(STW -Stop the world)。

    l?并發(fā)標(biāo)記:GC Root 開始對堆中對象進(jìn)行可達(dá)性分析,找到存活對象,它在整個回收過程中耗時最長,不需要停頓。

    l?重新標(biāo)記:為了修正并發(fā)標(biāo)記期間因用戶程序繼續(xù)運作而導(dǎo)致標(biāo)記產(chǎn)生變動的那一部分對象的標(biāo)記記錄,需要停頓(STW)。這個階段的停頓時間一般會比初始標(biāo)記階段稍長一些,但遠(yuǎn)比并發(fā)標(biāo)記的時間短。

    l?并發(fā)清除:不需要停頓。

    ?

    優(yōu)點:

    由于整個過程中耗時最長的并發(fā)標(biāo)記和并發(fā)清除過程收集器線程都可以與用戶線程一起工作,所以,從總體上來說,CMS收集器的內(nèi)存回收過程是與用戶線程一起并發(fā)執(zhí)行的。

    缺點:

    CPU資源敏感:因為并發(fā)階段多線程占據(jù)CPU資源,如果CPU資源不足,效率會明顯降低。

    浮動垃圾由于CMS并發(fā)清理階段用戶線程還在運行著,伴隨程序運行自然就還會有新的垃圾不斷產(chǎn)生,這一部分垃圾出現(xiàn)在標(biāo)記過程之后,CMS無法在當(dāng)次收集中處理掉它們,只好留待下一次GC時再清理掉。這一部分垃圾就稱為“浮動垃圾”。

    由于浮動垃圾的存在,因此需要預(yù)留出一部分內(nèi)存,意味著 CMS 收集不能像其它收集器那樣等待老年代快滿的時候再回收。

    1.6的版本中老年代空間使用率閾值(92%)

    如果預(yù)留的內(nèi)存不夠存放浮動垃圾,就會出現(xiàn) Concurrent Mode Failure,這時虛擬機將臨時啟用 Serial Old 來替代 CMS

    會產(chǎn)生空間碎片:標(biāo)記 - 清除算法會導(dǎo)致產(chǎn)生不連續(xù)的空間碎片

    ?

    G1垃圾回收器

    ?

    G1中重要的參數(shù):

    -XX:+UseG1GC ??使用G1垃圾回收器

    ?

    內(nèi)部布局改變

    G1 把堆劃分成多個大小相等的獨立區(qū)域(Region),新生代和老年代不再物理隔離。

    算法:標(biāo)記—整理 (humongous) 和復(fù)制回收算法(survivor)

    ?

    GC模式
    Young GC

    選定所有年輕代里的Region。通過控制年輕代的region個數(shù),即年輕代內(nèi)存大小,來控制young GC的時間開銷。(復(fù)制回收算法)

    Mixed GC

    選定所有年輕代里的Region,外加根據(jù)global concurrent marking統(tǒng)計得出收集收益高的若干老年代Region。在用戶指定的開銷目標(biāo)范圍內(nèi)盡可能選擇收益高的老年代Region

    Mixed GC不是full GC,它只能回收部分老年代的Region。如果mixed GC實在無法跟上程序分配內(nèi)存的速度,導(dǎo)致老年代填滿無法繼續(xù)進(jìn)行Mixed GC,就會使用serial old GCfull GC)來收集整個GC heap。所以我們可以知道,G1是不提供full GC的。

    全局并發(fā)標(biāo)記(global concurrent marking

    ?

    初始標(biāo)記:僅僅只是標(biāo)記一下GC Roots 能直接關(guān)聯(lián)到的對象,并且修改TAMSNest Top Mark Start)的值,讓下一階段用戶程序并發(fā)運行時,能在正確可以的Region中創(chuàng)建對象,此階段需要停頓線程(STW),但耗時很短。

    ?

    并發(fā)標(biāo)記:GC Root 開始對堆中對象進(jìn)行可達(dá)性分析,找到存活對象,此階段耗時較長,但可與用戶程序并發(fā)執(zhí)行。

    ?

    最終標(biāo)記:為了修正在并發(fā)標(biāo)記期間因用戶程序繼續(xù)運作而導(dǎo)致標(biāo)記產(chǎn)生變動的那一部分標(biāo)記記錄,虛擬機將這段時間對象變化記錄在線程的 Remembered Set Logs 里面,最終標(biāo)記階段需要把 Remembered Set Logs 的數(shù)據(jù)合并到 Remembered Set 中。這階段需要停頓線程(STW),但是可并行執(zhí)行。

    ?

    篩選回收:首先對各個 Region 中的回收價值和成本進(jìn)行排序,根據(jù)用戶所期望的 GC 停頓時間來制定回收計劃。此階段其實也可以做到與用戶程序一起并發(fā)執(zhí)行,但是因為只回收一部分 Region,時間是用戶可控制的,而且停頓用戶線程將大幅度提高收集效率。

    ?

    ?

    特點

    空間整合:不會產(chǎn)生內(nèi)存碎片

    算法:標(biāo)記—整理 (humongous) 和復(fù)制回收算法(survivor)

    可預(yù)測的停頓:

    G1收集器之所以能建立可預(yù)測的停頓時間模型,是因為它可以有計劃地避免在整個Java堆中進(jìn)行全區(qū)域的垃圾收集。G1跟蹤各個Region里面的垃圾堆積的價值大小(回收所獲得的空間大小以及回收所需時間的經(jīng)驗值),在后臺維護(hù)一個優(yōu)先列表,每次根據(jù)允許的收集時間,優(yōu)先回收價值最大的Region(這也就是Garbage-First名稱的來由)。這種使用Region劃分內(nèi)存空間以及有優(yōu)先級的區(qū)域回收方式,保證了G1收集器在有限的時間內(nèi)可以獲取盡可能高的收集效率。

    G1把內(nèi)存“化整為零”的思路,理解起來似

    G1 GC主要的參數(shù)

    參數(shù)

    含義

    -XX:G1HeapRegionSize=n

    設(shè)置Region大小,并非最終值

    -XX:MaxGCPauseMillis

    設(shè)置G1收集過程目標(biāo)時間,默認(rèn)值200ms,不是硬性條件

    -XX:G1NewSizePercent

    新生代最小值,默認(rèn)值5%

    -XX:G1MaxNewSizePercent

    新生代最大值,默認(rèn)值60%

    -XX:ParallelGCThreads

    STW期間,并行GC線程數(shù)

    -XX:ConcGCThreads=n

    并發(fā)標(biāo)記階段,并行執(zhí)行的線程數(shù)

    -XX:InitiatingHeapOccupancyPercent

    設(shè)置觸發(fā)標(biāo)記周期的 Java 堆占用率閾值。默認(rèn)值是45%。這里的java堆占比指的是non_young_capacity_bytes,包括old+humongous

    ?

    垃圾回收器的重要參數(shù)(使用-XX:

    參數(shù)

    描述

    UseSerialGC

    虛擬機運行在Client模式下的默認(rèn)值,打開此開關(guān)后,使用 Serial+Serial Old 的收集器組合進(jìn)行內(nèi)存回收

    UseParNewGC

    打開此開關(guān)后,使用 ParNew + Serial Old 的收集器組合進(jìn)行內(nèi)存回收

    UseConcMarkSweepGC

    打開此開關(guān)后,使用 ParNew + CMS + Serial Old 的收集器組合進(jìn)行內(nèi)存回收。Serial Old 收集器將作為 CMS 收集器出現(xiàn) Concurrent Mode Failure 失敗后的后備收集器使用

    UseParallelGC

    虛擬機運行在 Server 模式下的默認(rèn)值,打開此開關(guān)后,使用 Parallel Scavenge + Serial Old(PS MarkSweep) 的收集器組合進(jìn)行內(nèi)存回收

    UseParallelOldGC

    打開此開關(guān)后,使用 Parallel Scavenge + Parallel Old 的收集器組合進(jìn)行內(nèi)存回收

    SurvivorRatio

    新生代中 Eden 區(qū)域與 Survivor 區(qū)域的容量比值,默認(rèn)為8,代表 Eden : Survivor = 8 : 1

    PretenureSizeThreshold

    直接晉升到老年代的對象大小,設(shè)置這個參數(shù)后,大于這個參數(shù)的對象將直接在老年代分配

    MaxTenuringThreshold

    晉升到老年代的對象年齡,每個對象在堅持過一次 Minor GC 之后,年齡就增加1,當(dāng)超過這個參數(shù)值時就進(jìn)入老年代

    UseAdaptiveSizePolicy

    動態(tài)調(diào)整 Java 堆中各個區(qū)域的大小以及進(jìn)入老年代的年齡

    HandlePromotionFailure

    是否允許分配擔(dān)保失敗,即老年代的剩余空間不足以應(yīng)付新生代的整個 Eden Survivor 區(qū)的所有對象都存活的極端情況

    ParallelGCThreads

    設(shè)置并行GC時進(jìn)行內(nèi)存回收的線程數(shù)

    GCTimeRatio

    GC 時間占總時間的比率,默認(rèn)值為99,即允許 1% GC時間,僅在使用 Parallel Scavenge 收集器生效

    MaxGCPauseMillis

    設(shè)置 GC 的最大停頓時間,僅在使用 Parallel Scavenge 收集器時生效

    CMSInitiatingOccupancyFraction

    設(shè)置 CMS 收集器在老年代空間被使用多少后觸發(fā)垃圾收集,默認(rèn)值為 68%,僅在使用 CMS 收集器時生效

    UseCMSCompactAtFullCollection

    設(shè)置 CMS 收集器在完成垃圾收集后是否要進(jìn)行一次內(nèi)存碎片整理,僅在使用 CMS 收集器時生效

    CMSFullGCsBeforeCompaction

    設(shè)置 CMS 收集器在進(jìn)行若干次垃圾收集后再啟動一次內(nèi)存碎片整理,僅在使用 CMS 收集器時生效

    ?

    Stop The World現(xiàn)象

    GC收集器和我們GC調(diào)優(yōu)的目標(biāo)就是盡可能的減少STW的時間和次數(shù)。

    轉(zhuǎn)載于:https://www.cnblogs.com/Soy-technology/p/11020638.html

    創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎

    總結(jié)

    以上是生活随笔為你收集整理的垃圾回收算法与垃圾回收器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。