垃圾回收機制(GC)

目錄

垃圾回收機制

引用計數法

可達性分析算法

垃圾回收算法

標記清除算法

復制算法

標記壓縮算法

JVM中一次完整的GC(分代收集算法)

在新生代中

在老年代中

空間分配擔保原則

對象從新生代進入老年代的幾種情況?

Young GC?和 Full GC

垃圾回收器

CMS的回收過程

G1的回收過程


垃圾就是那些不再被程序使用,但仍然占據內存空間沒有被釋放的對象。

垃圾回收機制

引用計數法

  • 每個對象有一個引用計數器,記錄有多少個引用指向該對象,有一個引用則+1。當計數器歸零時,該對象被認為是垃圾。
  • 這個方法存在循環引用的問題,即使AB兩個對象不再被程序其他地方使用,但如果它們之間存在相互引用,計數器永遠不會歸零,也就永遠不會被定義成垃圾?。

可達性分析算法

  • 這是Java中常用的垃圾回收方式。從 Gc Root 出發可以通過引用訪問到的的對象不會被當作垃圾對象,即一個對象被 GcRoot 直接 或 間接持有,那么該對象就不會被當作垃圾對象。那些不可達的對象肯定就是垃圾了,直接清理掉即可。
    • GC Root 就是一些特殊的引用。如:
      • 棧中局部變量
      • 方法區中靜態變量
      • 本地方法棧JNI引用的對象
      • 被同步鎖持有的對象

但一個對象被認為是垃圾后,不會馬上被回收,還需要進行兩次標記

  • 第一次標記:判斷當前對象是否有finalize()方法并且該方法沒有被執行過,若不存在則標記為垃圾對象,等待回收;若有的話,則進行第二次標記;?
  • 第二次標記將當前對象放入F-Queue隊列,并生成一個finalize線程去執行該方法,虛擬機不保證該方法一定會被執行,這是因為如果線程執行緩慢或進入了死鎖,會導致回收系統的崩潰;如果執行了finalize方法之后仍然沒有與GC Roots有直接或者間接的引用,則該對象會被回收;

垃圾回收算法

標記清除算法

分標記和清除兩階段來進行垃圾收集工作:

  • 標記:通過GC Roots可達的對象進行標記,即堆所有存活(可用)的對象進行標記
  • 清除:對整個堆內存空間進行掃描,如果發現某個對象未被標記為可達對象,那么將其回收

優點:實現簡單,執行效率高

缺點:容易產生 內存碎片(可用內存分布比較分散 不連續),如果需要申請大塊連續內存可能會頻繁觸發 GC

復制算法

將內存分為兩塊,每次只是用其中一塊。首先遍歷所有對象,將可用對象復制到另一塊內存中,此時上一塊內存可視為全是垃圾,清理后將新內存塊置為當前可用。如此反復進行。

優點:解決了內存碎片的問題

缺點:需要按順序分配內存,可用內存變為原來的一半。

標記壓縮算法

和標記清除算法類似,分為兩步:?

  • 標記:通過GC Roots可達的對象進行標記,即堆所有存活(可用)的對象進行標記
  • 壓縮:將所有存活對象往一端空閑空間移動,按照內存地址依次排序,并更新對應引用的指針,然后清理末端內存地址以外的全部內存空間

優點:解決了標記清除的 內存碎片 問題 ,也不需要復制算法中的 內存分塊,彌補了浪費一半內存空間的缺點。

缺點:仍需要將對象進行移動,使用成本更高。執行效率略低。

JVM中一次完整的GC(分代收集算法)

在新生代中

  • 一個對象剛被創建時會放到 Eden 區,Eden 區即將存滿時做一次垃圾回收(Minor GC),將當前存活的對象復制到 幸存0區(from區) ,隨后將 Eden 清空
  • 當Eden 下一次存滿時,再做一次垃圾回收,先將存活對象復制到 幸存1區(to區) ,再把 Eden 和 幸存0區 所有對象進行回收,
  • 當Eden 再一次存滿時,再做一次垃圾回收,將存活對象復制到 幸存0區,再把 Eden 和 幸存1區 對象進行回收。如此反復進行大概 15 次,將最終依舊存活的對象放入到老年代區域。
  • 新生代工作流程與 復制算法 應用場景較為吻合,都是以復制為核心,所以會采用復制算法

在老年代中

  • 當一個對象存活時間較久會被存入到 老年代 區域。 老年代 區即將被存滿時會做一次垃圾回收,
  • 所以 老年代 區域特點是存活對象多、垃圾對象少,采用標記壓縮算法時移動少、也不會產生內存碎片。所以老年代 區域可以選用 標記清除或標記壓縮算法 進行垃圾收集。

空間分配擔保原則

  • JVM有一個老年代空間分配擔保機制來保證對象能夠進入老年代。?
    • 如果YougGC時新生代有大量對象存活下來,而 survivor 區放不下了,這時必須轉移到老年代中,但這時發現老年代也放不下這些對象了,于是JVM有一個老年代空間分配擔保機制來保證對象能夠進入老年代。
  • 在執行每次 YoungGC 之前,JVM會先檢查老年代最大可用連續空間是否大于新生代所有對象的總大小。因為在極端情況下,可能新生代 YoungGC 后,所有對象都存活下來了,而 survivor 區又放不下,那可能所有對象都要進入老年代了。
    • 如果老年代的可用連續空間是大于新生代所有對象的總大小的,那就可以放心進行 YoungGC。
    • 如果老年代的內存大小是小于新生代對象總大小的,那就有可能老年代空間不夠放入新生代所有存活對象。
    • 這時JVM就會先檢查 -XX:HandlePromotionFailure 參數是否允許擔保失敗。
      • 如果允許,就會判斷老年代最大可用連續空間是否大于歷次晉升到老年代對象的平均大小。
        • 如果大于,將嘗試進行一次YoungGC,盡快這次YoungGC是有風險的。
        • 如果小于,或者 -XX:HandlePromotionFailure 參數不允許擔保失敗,這時就會進行一次 Full GC。
    • 在允許擔保失敗并嘗試進行YoungGC后,可能會出現三種情況:?
      • ① YoungGC后,存活對象小于survivor大小,此時存活對象進入survivor區中?
      • ② YoungGC后,存活對象大于survivor大小,但是小于老年大可用空間大小,此時直接進入老年代。?
      • ③ YoungGC后,存活對象大于survivor大小,也大于老年大可用空間大小,老年代也放不下這些對象了,此時就會發生“Handle Promotion Failure”,就觸發了 Full GC。如果 Full GC后,老年代還是沒有足夠的空間,此時就會發生OOM內存溢出了。

對象從新生代進入老年代的幾種情況?

?對象年齡達到指定閾值?:默認情況下,對象的年齡達到15次GC后會被晉升到老年代。這個閾值可以通過JVM參數-XX:MaxTenuringThreshold進行設置?。

?動態年齡判斷?:如果Survivor區中相同年齡的所有對象大小總和大于Survivor空間的一半,年齡大于或等于該年齡的對象可以直接進入老年代?。

?大對象直接進入老年代?:如果對象的大小超過了設定的閾值(默認是1MB),可以直接在老年代中分配,避免在新生代中頻繁進行垃圾回收?。

?Young GC后存活對象超過Survivor區大小?:在Young GC后,如果存活的對象超過了Survivor區的大小,這些對象會被直接晉升到老年代?。

Young GC?和 Full GC

  • Young GC:只收集新生代的GC。?
  • Full GC: 收集整個堆,包括 新生代,老年代,永久代(在 JDK 1.8及以后,永久代被移除,換為metaspace 元空間)等所有部分的模式。?
  • Young GC觸發條件:當Eden區滿時,觸發Minor GC。?
  • Full GC觸發條件:?
    • 通過Minor GC后 進入老年代的平均大小大于老年代的可用內存。如果發現統計數據說之前Minor GC的平均晉升大小比目前老年代剩余的空間大,則不會觸發Minor GC而是轉為觸發full GC。
    • 老年代空間不夠分配新的內存(或永久代空間不足,但只是JDK1.7有的,這也是用元空間來取代永久代的原因,可以減少Full GC的頻率,減少GC負擔,提升其效率)。?
    • Eden區、From Space區向To Space區復制時,對象大小大于To Space可用內存,則把該對象轉存到老年代,且老年代的可用內存小于該對象大小。?
    • 調用System.gc時,系統建議執行Full GC,但是不必然執行。

垃圾回收器

  • 垃圾回收器主要分為以下幾種:Serial、ParNew、Parallel Scavenge、Serial Old、Parallel Old、CMS、G1,主流的垃圾回收器:CMS、G1
    • Serial:單線程的收集器,收集垃圾時,必須stop the world,使用復制算法。它的最大特點是在進行垃圾回收時,需要對所有正在執行的線程暫停(stop the world),對于有些應用是難以接受的,但是如果應用的實時性要求不是那么高,只要停頓的時間控制在N毫秒之內,大多數應用還是可以接受的,是client級別的默認GC方式。?
    • ParNew:Serial收集器的多線程版本,也需要stop the world,復制算法。?
    • Parallel Scavenge:新生代收集器,復制算法的收集器,并發的多線程收集器,目標是達到一個可控的吞吐量,和ParNew的最大區別是GC自動調節策略;虛擬機會根據系統的運行狀態收集性能監控信息,動態設置這些參數,以提供最優停頓時間和最高的吞吐量;?
    • Serial Old:Serial收集器的老年代版本,單線程收集器,使用標記整理算法。?
    • Parallel Old:是Parallel Scavenge收集器的老年代版本,使用多線程,標記-整理算法。?
    • CMS:是一種以獲得最短回收停頓時間為目標的收集器,標記清除算法,運作過程:初始標記,并發標記,重新標記,并發清除,收集結束會產生大量空間碎片;?
    • G1:標記整理算法實現,運作流程主要包括以下:初始標記,并發標記,最終標記,篩選回收。不會產生空間碎片,可以精確地控制停頓;G1將整個堆分為大小相等的多個Region(區域),G1跟蹤每個區域的垃圾大小,在后臺維護一個優先級列表,每次根據允許的收集時間,優先回收價值最大的區域,已達到在有限時間內獲取盡可能高的回收效率;

CMS的回收過程

  • CMS (Concurrent Mark Sweep,并發標記清除) 收集器是以獲取最短回收停頓時間為目標的收集器(追求低停頓),它在垃圾收集時使得用戶線程和 GC 線程并發執行,因此在垃圾收集過程中用戶也不會感到明顯的卡頓。?
    STW "Stop-The-World" ,指的是垃圾收集器在進行垃圾回收時,會暫停應用程序的運行,這個停頓的時間稱為停頓時間(Pause Time)。停頓時間是指垃圾回收器在執行垃圾回收時,導致應用程序無法繼續執行的時間段
  • 從名字就可以知道,CMS是基于“標記-清除”算法實現的。CMS 回收過程分為以下四步:?
    • a.初始標記 (CMS initial mark):主要是標記 GC Root 開始的下級(注:僅下一級)對象,這個過程會 STW,但是跟 GC Root 直接關聯的下級對象不會很多,因此這個過程其實很快。
      STW(stop the world)時間不會很長、確保盡可能數據正確
    • b.并發標記 (CMS concurrent mark):根據上一步的結果,繼續向下標識所有關聯的對象,直到這條鏈上的最盡頭。這個過程是多線程的,雖然耗時理論上會比較長,但是其它工作線程并不會阻塞,沒有 STW。
    • c.重新標記(CMS remark):就是要再標記一次。因為第 2 步并沒有阻塞其它工作線程,其它線程在標識過程中,很有可能會產生新的垃圾。會STW。(錯標、漏標)
    • d.并發清除(CMS concurrent sweep):清除階段是清理刪除掉標記階段判斷的已經死亡的對象,由于不需要移動存活對象,所以這個階段也是可以與用戶線程同時并發進行的。
  • CMS 的問題:?
    • 1、并發回收導致CPU資源緊張:
      • 在并發階段,它雖然不會導致用戶線程停頓,但卻會因為占用了一部分線程而導致應用程序變慢,降低程序總吞吐量。CMS默認啟動的回收線程數是:(CPU核數 + 3)/ 4,當CPU核數不足四個時,CMS對用戶程序的影響就可能變得很大。?
    • 2、無法清理浮動垃圾:
      • 在CMS的并發標記和并發清理階段,用戶線程還在繼續運行,就還會伴隨有新的垃圾對象不斷產生,但這一部分垃圾對象是出現在標記過程結束以后,CMS無法在當次收集中處理掉它們,只好留到下一次垃圾收集時再清理掉。這一部分垃圾稱為“浮動垃圾”。?
    • 3、并發失敗(Concurrent Mode Failure):
      • 由于在垃圾回收階段用戶線程還在并發運行,那就還需要預留足夠的內存空間提供給用戶線程使用,因此CMS不能像其他回收器那樣等到老年代幾乎完全被填滿了再進行回收,必須預留一部分空間供并發回收時的程序運行使用。默認情況下,當老年代使用了 92% 的空間后就會觸發 CMS 垃圾回收,這個值可以通過 -XX: CMSInitiatingOccupancyFraction 參數來設置。?
      • 這里會有一個風險:要是CMS運行期間預留的內存無法滿足程序分配新對象的需要,就會出現一次“并發失敗”(Concurrent Mode Failure),這時候虛擬機將不得不啟動后備預案:Stop The World,臨時啟用 Serial Old 來重新進行老年代的垃圾回收,這樣一來停頓時間就很長了。?
    • 4、內存碎片問題:?
      • CMS是一款基于“標記-清除”算法實現的回收器,這意味著回收結束時會有內存碎片產生。內存碎片過多時,將會給大對象分配帶來麻煩,往往會出現老年代還有很多剩余空間,但就是無法找到足夠大的連續空間來分配當前對象,而不得不提前觸發一次 Full GC 的情況。?
      • 為了解決這個問題,CMS收集器提供了一個 -XX:+UseCMSCompactAtFullCollection 開關參數(默認開啟),用于在 Full GC 時開啟內存碎片的合并整理過程,由于這個內存整理必須移動存活對象,是無法并發的,這樣停頓時間就會變長。還有另外一個參數 -XX:CMSFullGCsBeforeCompaction,這個參數的作用是要求CMS在執行過若干次不整理空間的 Full GC 之后,下一次進入 Full GC 前會先進行碎片整理(默認值為0,表示每次進入 Full GC 時都進行碎片整理)。?

G1的回收過程

  • 整體: 標記-壓縮 算法實現的回收器,局部: 標記-復制 算法實現。
  • G1(Garbage First)回收器采用面向局部收集的設計思路和基于Region的內存布局形式,是一款主要面向服務端應用的垃圾回收器。G1設計初衷就是替換 CMS,成為一種全功能收集器。G1 在JDK9 之后成為服務端模式下的默認垃圾回收器,取代了 Parallel Scavenge 加 Parallel Old 的默認組合,而 CMS 被聲明為不推薦使用的垃圾回收器。G1從整體來看是基于 標記-壓縮 算法實現的回收器,但從局部(兩個Region之間)上看又是基于 標記-復制 算法實現的。
  • G1 回收過程,G1 回收器的運作過程大致可分為四個步驟:?
    • a.初始標記(會STW):僅僅只是標記一下 GC Roots 能直接關聯到的對象,并且修改TAMS指針的值,讓下一階段用戶線程并發運行時,能正確地在可用的Region中分配新對象。這個階段需要停頓線程,但耗時很短,而且是借用進行Minor GC的時候同步完成的,所以G1收集器在這個階段實際并沒有額外的停頓。
    • b.并發標記:從 GC Roots 開始對堆中對象進行可達性分析,遞歸掃描整個堆里的對象圖,找出要回收的對象,這階段耗時較長,但可與用戶程序并發執行。當對象圖掃描完成以后,還要重新處理在并發時有引用變動的對象。
    • c.最終標記(會STW):對用戶線程做短暫的暫停,處理并發階段結束后仍有引用變動的對象。
    • d.清理階段(會STW):更新Region的統計數據,對各個Region的回收價值和成本進行排序,根據用戶所期望的停頓時間來制定回收計劃,可以自由選擇任意多個Region構成回收集,然后把決定回收的那一部分Region的存活對象復制到空的Region中,再清理掉整個舊Region的全部空間。這里的操作涉及存活對象的移動,必須暫停用戶線程,由多條回收器線程并行完成的。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/94882.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/94882.shtml
英文地址,請注明出處:http://en.pswp.cn/web/94882.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

DNS域名系統

DNS域名系統一、什么是DNS?二、DNS的域名層級1. 根域2. 頂級域3. 二級域4. 三級域(子域)5. 主機名三、DNS服務器的分類四、DNS的解析過程五、DNS的記錄類型六、FQDN(完全限定域名)一、什么是DNS? DNS(Domain Name S…

虛擬內存和虛擬頁面

虛擬內存虛擬內存是現代操作系統提供的一種內存管理機制,它允許程序訪問比實際物理內存更大的地址空間。虛擬內存通過將程序的地址空間劃分為多個固定大小的塊(稱為頁面),并將這些頁面映射到物理內存或磁盤上的頁面文件中&#xf…

【2025年電賽E題】基于k230的矩形框識別鎖定1

文章目錄 概要 整體架構流程 技術名詞解釋 技術細節 1. 多閾值適配與目標識別邏輯 2. 動態ROI與狀態管理機制 3. 數據平滑與偏差計算 4. 硬件適配與UART通信 小結 靜態矩形框識別 動態矩形框追蹤 概要 本文分析的代碼是基于立創廬山派K230CanMV開發板的目標追蹤系統實現,主要…

c語言中的數組可以用int a[3]來創建。寫一次int就可以了,而java中要聲明兩次int類型像這樣:int[] arr = new int[3];

C 語言數組只需寫一次int,而 Java 需兩次int相關聲明,核心原因是兩種語言的數組本質定義、類型系統設計和內存管理邏輯完全不同,具體可拆解為兩點核心差異:一、C 語言:數組是 “內存塊的類型綁定”,一次聲明…

深度學習——詳細教學:神經元、神經網絡、感知機、激活函數、損失函數、優化算法(梯度下降)

神經網絡實戰: 深度學習——神經網絡簡單實踐(在乳腺癌數據集上的小型二分類示例)-CSDN博客https://blog.csdn.net/2302_78022640/article/details/150779819?spm1001.2014.3001.5502 深度學習——神經網絡(PyTorch 實現 MNIST…

Ubuntu 軟件安裝的五種方法

1、App Store 安裝 Ubuntu 里面有 一個App叫 “Ubuntu軟件” 2、Sudo apt-get install 安裝法 注意 使用apt工具安裝軟件,需要sudo,也就是root權限 例子 apt -get install git 會提示查看是否以root用戶運行,install-安裝sudo a…

Day15 (前端:JavaScript基礎階段)

接續上文:Day14——JavaScript 核心知識全解析:變量、類型與操作符深度探秘-CSDN博客 點關注不迷路喲。你的點贊、收藏,一鍵三連,是我持續更新的動力喲!!! 主頁:一位搞嵌入式的 genius-CSDN博…

在線旅游及旅行管理系統項目SQL注入

1.前言 之前在網上隨便逛逛的時候,發現一個有各種各樣的PHP項目的管理系統,隨便點進一個查看,發現還把mysql版本都寫出來了,而且還是PHP語言。 https://itsourcecode.com/free-projects/php-project/online-tours-and-travels-m…

Java網絡編程(UDP, TCP, HTTP)

1. OSI 七層網絡模型層級名稱核心功能協議示例數據單元7應用層提供用戶接口和網絡服務HTTP, FTP, SMTP, DNS報文6表示層數據格式轉換、加密/解密、壓縮/解壓SSL, JPEG, MPEG數據流5會話層建立、管理和終止會話連接NetBIOS, RPC會話數據4傳輸層端到端可靠傳輸、流量控制、差錯校…

【P2P】P2P主要技術及RELAY服務1:python實現

P2P 技術 P2P(點對點)網絡的核心是去中心化的網絡拓撲和通信協議。DP的應用相對較少,但可能出現在: 路由優化:在一些復雜的P2P網絡中,一個節點需要向另一個節點發送消息。為了找到一條延遲最低或跳數最少的路徑,可能會用到類似最短路徑的算法,而這類算法(如Bellman-F…

docker 安裝 redis 并設置 volumes 并修改 修改密碼(一)

在 Docker 中安裝 Redis 并設置volumes持久化數據,同時修改 Redis 密碼的完整步驟如下: 安裝 Docker 如果還沒有安裝 Docker,可以參考以下步驟安裝: 在 Alibaba Cloud Linux 上安裝 Docker # 更新系統 sudo yum update -y# 安裝 Docker 依賴 sudo yum install -y yum-util…

如何找出所有連接到本機指定端口的客戶端 IP

在日常運維或排查網絡問題時,我們常常需要知道:有哪些客戶端正在連接我的服務?連接數是否異常?是否存在惡意掃描或 DDoS 行為?本文將教你使用一條簡潔高效的 Linux 命令組合,統計連接到本機某個端口&#x…

java IDE安裝idea社區版步驟

IntelliJ IDEA 社區版(Community Edition)是一款功能強大且完全免費的集成開發環境,非常適合 Java 和 Kotlin 初學者或進行基礎開發2。我會為你提供詳細的安裝步驟。 🛠 IntelliJ IDEA 社區版安裝指南 📋 系統要求與…

Agent智能體

什么是 Agent? Agent 是一個智能體,可以接收用戶請求,利用大模型(LLM)的推理能力,自動決定: 自己回答還是調用外部工具(數據庫、API、腳本等) 最終把結果返回給用戶。 能…

【VSCode】使用VSCode打開md文件以及轉化為PDF

【VSCode】使用VSCode打開md文件以及轉化為PDF在 Visual Studio Code (VS Code) 中渲染 Markdown 并保存為 PDF,可以通過以下步驟實現。 首先安裝好 VSCode,可以參考下述鏈接 https://blog.csdn.net/weixin_43848614/article/details/148042035 安裝m…

蘋果ImageIO零日漏洞分析:攻擊背景與iOS零點擊漏洞歷史對比

蘋果公司已緊急發布全生態系統安全更新,修復編號為CVE-2025-43300的ImageIO框架高危零日漏洞(zero-day),該漏洞已被用于復雜的定向攻擊。這是蘋果在2025年修復的第七個零日漏洞,凸顯iOS和macOS設備面臨的威脅持續升級。…

面試 TOP101 遞歸/回溯專題題解匯總Java版(BM55 —— BM61)

8月刷題挑戰,多重好禮等你拿 遞歸/回溯 題號題目名稱核心思路時間復雜度空間復雜度代碼亮點牛客原題鏈接BM55沒有重復項數字的全排列使用回溯法生成所有排列O(n!)O(n)使用回溯法生成所有排列,邏輯清晰🔗 直達BM56有重復項數字的全排列使用回…

音頻相關數學知識

時域(Time domain)是描述數學函數或物理信號對時間的關系,如果聲音對應頻率正負波動,對應事件x軸為時間,y軸為振幅頻域信號在頻率方面特性,如射頻范圍正弦型函數可以用來虛擬音頻,正弦&#xff…

SAP-ABAP:SAP HANA 架構解析:主從(Scale-Out)與主備(High Availability)架構深度對比

SAP HANA 架構解析:主從(Scale-Out)與主備(High Availability)架構深度對比 一、架構概述 在SAP HANA數據庫系統中,兩種核心架構模式解決了不同的業務需求:主從架構(Scale-Out&#…

【Hadoop】HDFS 分布式存儲系統

Namenode是整個HDFS文件系統的前端,只有一個,管理數據塊映射信息,配置副本策略,處理客戶端的讀寫請求。Secondary namenode是namenode的熱備,當active namenode出現故障時,快速切換為新的active namenode。…