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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

G1 垃圾回收器

發布時間:2023/12/20 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 G1 垃圾回收器 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、垃圾收集器簡介

1、發展歷程

  • 第一階段,Serial(串行)收集器
    在jdk1.3.1之前,java虛擬機僅僅能使用Serial收集器。 Serial收集器是一個單線程的收集器,但它的“單線程”的意義并不僅僅是說明它只會使用一個CPU或一條收集線程去完成垃圾收集工作,更重要的是在它進行垃圾收集時,必須暫停其他所有的工作線程,直到它收集結束。

  • 第二階段,Parallel(并行)收集器
    Parallel收集器也稱吞吐量收集器,相比Serial收集器,Parallel最主要的優勢在于使用多線程去完成垃圾清理工作,這樣可以充分利用多核的特性,大幅降低gc時間。

  • 第三階段,CMS(并發)收集器
    CMS收集器在Minor GC時會暫停所有的應用線程,并以多線程的方式進行垃圾回收。在Full GC時不再暫停應用線程,而是使用若干個后臺線程定期的對老年代空間進行掃描,及時回收其中不再使用的對象。

  • 第四階段,G1(并發)收集器
    G1收集器(或者垃圾優先收集器)的設計初衷是為了盡量縮短處理超大堆(大于4GB)時產生的停頓。相對于CMS的優勢而言是內存碎片的產生率大大降低。

2、種類

  • 新生代

    • Serial (第一代)
    • PraNew (第二代)
    • Parallel Scavenge (第三代)
    • G1收集器(第四代)
  • 老年代

    • Serial Old (第一代)
    • Parallel Old (第二代)
    • CMS (第三代)
    • G1

二、G1 介紹

1、概述

  • G1收集器的最大特點
    • G1最大的特點是引入分區的思路,弱化了分代的概念
    • 合理利用垃圾收集各個周期的資源,解決了其他收集器甚至CMS的眾多缺陷
  • G1相比較CMS的改進
    • 算法:基于標記-整理算法,不會產生空間碎片,分配大對象時不會因得不到連續空間而提前觸發 FULL GC
    • 停頓時間可控: G1可以通過設置預期停頓時間 Pause Time 來控制垃圾收集時間避免應用雪崩現象
    • 并行與并發:G1 能充分利用 多核 CPU 的硬件優勢來縮短 stop the world 的停頓時間
  • CMS和G1的區別
    • CMS 的堆分為 PermGen、YoungGen、OldGen;而YoungGen又分了兩個survivo區域
      G1 的堆被分為區域(region),每個區域雖然保留了新老代概念,但收集器是以整個區域為單位收集
    • G1在回收內存后會馬上同時做合并空閑內存的工作、而 CMS 默認是在STW(stop the world)時做
    • G1會在 Young GC 中使用、而 CMS 只能在 O 區使用
  • G1收集器的應用場景
    • G1垃圾收集算法主要應用在多CPU大內存的服務中,在滿足高吞吐量的同時,盡可能的滿足垃圾回收時的暫停時間。
    • 就目前而言、CMS還是默認首選的GC策略、可能在以下場景下G1更適合:
      • 服務端多核CPU、JVM內存占用較大的應用(至少大于4G)
      • 應用在運行過程中會產生大量內存碎片、需要經常壓縮空間
      • 想要更可控、可預期的GC停頓周期,防止高并發下應用雪崩現象
  • 2、G1的堆內存算法

    G1之前的JVM內存模型


    G1收集器的內存模型

    • G1 收集器將整個Java 堆劃分成約 2048 個大小相同的獨立 Region 塊,每個Region塊大小根據堆空間的實際大小而定

      可以通過 -XX :G1HeapRegionSize 設定,值在 1MB~32MB 之間且為 2 的次冪

    • region 可能屬于 Eden、Survivor、0ld、Humongous 區域,但一個region只可能屬于一個角色

    • Humongous 作用:用來專門存放大對象,一般使用連續 region 區存儲,G1的大多數行為都把H區
      作為老年代的一部分來看待

    3、G1 的特點、缺點

    3.1 特點

    ①. 并行和并發

    • 并行性:G1 在回收期間,可以有多個GC線程同時工作,有效利用多核計算能力
    • 并發性:G1擁有與應用程序交替執行的能力,部分工作可以和應用程序同時執行

    ②. 分代收集

    • 從分代上看,G1 仍屬于分代型垃圾回收器,會區分年輕代和老年代,年輕代依然有 Eden 區和 Survivor 區
      但從堆的結構上看,不要求整個 Eden 區、年輕代或老年代都連續,也不再堅持固定大小和固定數量
    • 將堆空間分為若干個區域(Region),這些區域中包含了邏輯上的年輕代和老年代
    • 和之前的各類回收器不同,其同時兼顧年輕代和老年代

    ③. 空間整合

    • 內存回收以 region 為基本單位,Region之間是復制算法,但整體是標記-壓縮算法,可以避免內存碎片,有利于程序長時間運行,分配大對象時不會因為無法找到連續內存空間而提前觸發下一次GC

    ④. 可預測的停頓時間模型(即:軟實時soft real一time)
    可預測的停頓時間模型:能讓使用者明確指定在一個長度為 M 毫秒的時間片段內,消耗在垃圾收集上的時間不得超過 N 毫秒,通過參數 -XX:MaxGCPauseMillis 設置

    • 由于分區的原因,G1可以只選取部分區域進行內存回收,縮小回收范圍,避免全局停頓情況的發生
    • G1 跟蹤各個 Region 中垃圾堆積的價值大小(回收所獲得的空間大小以及回收所需時間的經驗值),在后臺維護一個優先列表,每次根據允許的收集時間,優先回收價值最大的 Region,保證了G1收集器在有限的時間內可以獲取盡可能高的收集效率。
    • 相比于 CMS GC,G1未必能做到CMS在最好情況下的延時停頓,但最差情況要好很多

    3.2 缺點

    • 相較于CMS,G1 還不具備全方位、壓倒性優勢,如:G1 無論是為了垃圾收集產生的內存占用,還是程序運行時的額外執行負載都要比 CMS 高
    • 小內存應用上,CMS 的表現大概率會優于 G1,而 G1 在大內存應用上則發揮其優勢,平衡點在6-8GB之間

    4、G1 獨有概念

    4.1 RSet 與 card

    RSet 與 card 專門用來處理 Old 區到 Young 區的引用
    Young 區到 Old 區的引用不需要單獨處理,因為 Young 區中的對象本身變化比較大,沒必要浪費空間去記錄下來

    • RSet:用來記錄外部指向本 Region 的所有引用,每個 Region 維護一個 RSet
    • Card: JVM 將內存劃分成了固定大小的 Card,類比物理內存上 page 的概念
    • 每個 Region 分成多個 Card,其中綠色部分的 Card 表示該 Card 中有對象引用了其他 Card 中的對象,這種引用關系用藍色實線表示。
    • RSet 其實是一個HashTable,Key 是 Region 的起始地址,Value 是Card Table(字節數組),字節數組下標表示 Card 的空間地址,當該地址空間被引用時會被標記為 dirty_card

    RSet 的更新

    G1 采用 post-write barrier 和 concurrent refinement threads 更新 RSet,減少每次給引用類型的字段賦值都要更新 RSet帶來的開銷

    java 層面給 old 對象的 p 字段賦值 young 對象之后,jvm 底層會執行 oop_store 方法

    在賦值動作的前后,JVM插入一個 pre-write barrier 和 post-write barrier

    post-write barrier 的最終動作如下:

    • 找到該字段所在的位置(Card),并設置為 dirty_card
    • 若當前是應用線程,每個Java線程有一個 dirty card queue,把該 card 插入隊列
    • 除了每個線程自帶的 dirty card queue,還有一個全局共享的 queue

    RSet 更新操作交由多個 ConcurrentG1RefineThread 并發完成,每當全局隊列集合超過一定閾值后,ConcurrentG1RefineThread 會取出若干個隊列,遍歷每個隊列中記錄的card,并進行處理,大概實現邏輯如下:
    1、根據 card 的地址,計算出 card 所在的 Region
    2、若 Region 不存在,或 Region 是 Young 區,或該 Region 在回收集合中,則不進行處理
    3、最終使用閉合函數 G1UpdateRSOrPushRefOopClosure::do_oop_nv() 的處理該 card 中的對象

    refinement threads 線程數量可以通過 -XX:G1ConcRefinementThreads 或 -XX:ParallelGCThreads 參數設置

    4.2 Collection Set

    收集集合(CSet):一組可被回收的分區集合。在CSet中存活的數據會在GC過程中被移動到另一個可用分區,CSet中的分區可以來自eden空間、survivor空間、老年代

    GC時在CSet中的所有存活數據都會被轉移,分區釋放回空閑分區隊列

    4.3 PLAB

    在 GC 線程的晉升本地分配緩沖區(PLAB)中,對象晉升到 survivor 分區或老年代分區

    每個線程有獨立的PLAB,作用是避免多線程競爭相同數據

    4.4 TLAB

    JVM使用線程本地分配緩存TLAB 這種線程專屬的區間,來避免多線程沖突(無鎖方式),提高對象分配效率

    TLAB 本身占用了 Eden 空間,即 JVM 會為每一個線程都分配一塊 TLAB 空間

    5、G1 回收過程

    大致流程

  • 當 Eden 區用盡時,開始年輕代回收,而 G1 的年輕代收集階段是一個并行(多個垃圾線程)的獨占式收集器

    年輕代回收時,G1 暫停所有應用程序線程,啟動多線程執行年輕代回收,然后移動存活對象到Survivor 或 O 區

  • 當堆內存使用達到一定值(默認45%,-XX:InitiatingHeapOccupancyPercent)時,開始老年代并發標記過程
  • 標記完成馬上開始混合回收過程,此時 G1 從 O 區移動存活對象到空閑區間

    一次只需要掃描/回收一小部分老年代的 Region 就可以

  • 若 GC 的評估失敗,則提供失敗保護機制,即強力回收 FULL GC(單線程、獨占式、高強度)
  • 5.1 Young GC

    • 回收時機:當 Eden 空間耗盡時,G1會啟動一次年輕代垃圾回收過程
    • 回收對象:年輕代垃圾回收只會回收 Eden 區和 Survivor 區

    回收流程

    • 第一階段,根掃描,根引用連同 RSet 記錄的外部引用作為掃描存活對象的入口
      • 根是指 static 變量指向的對象,正在執行的方法調用鏈條上的局部變量等
      • 掃描 remembered Set,看是否有老年代中的對象引用了新生代對象
    • 第二階段,更新 RSet
      • 處理 dirty card queue 中的 card,更新 RSet 后,可以準確反映老年代對所在的內存分段中對象的引用
    • 第三階段,處理 RSet
      • 識別被老年代對象指向的 Eden 中的對象,這些被指向的 Eden 中的對象被認為是存活的對象
    • 第四階段,復制對象,遍歷對象樹
      • Eden 區內存段中存活的對象會被復制到 Survivor 區中空的內存分段
      • Survivor 區內存段中存活的對象如果年齡未達閾值,年齡會加1,達到閥值會被復制到 old 區中空的內存分段
      • 若 Survivor 空間不夠,Eden 空間的部分數據會直接晉升到老年代空間
    • 第五階段,處理引用,處理 Soft、Weak、Phantom、Final、JNI Weak 等引用
      • 最終 Eden 空間的數據為空,GC停止工作,而目標內存中的對象都是連續存儲的,沒有碎片,所以復制過程可以達到內存整理的效果,減少碎片

    5.2 Concurrent Marking

  • 初始標記階段:標記從根節點直接可達的對象,這個階段是 STW 的,并且會觸發一次年輕代 GC

  • 根區域掃描(Root Region Scanning):G1 GC 掃描 Survivor 區直接可達的老年代區域對象,并標記被引用的對象

    這一過程必須在 young GC 之前完成(YoungGC時,會動 Survivor 區,所以這一過程必須在young GC之前完成)

  • 并發標記(Concurrent Marking):在并發標記階段,若發現區域對象中的所有對象都是垃圾,則這個區域會被立即回收,此過程可能被 young GC 中斷

    并發標記過程中,會計算每個區域的對象活性(區域中存活對象的比例)

  • 再次標記(Remark):修正上一次的標記結果,是 STW

  • 獨占清理(cleanup,STW):計算各個區域的存活對象和 GC 回收比例,并進行排序,識別可以混合回收的區域,是STW 的

    這個階段并不會實際上去做垃圾的收集

  • 并發清理階段:識別并清理完全空閑的區域

  • 5.3 Mixed GC

    • 觸發時機:老年代的堆占有率達到參數 -XX:InitiatingHeapOccupancyPercent 設定的值則觸發
    • 回收對象:回收所有的 Young 和部分 Old(根據期望的GC停頓時間確定old區垃圾收集的優先順序)以及大對象區
    • 回收過程:MixedGC 主要使用復制算法,把各個 region 中存活的對象拷貝到別的 region 里去,拷貝過程中若發現沒有足夠的空 region 能夠承載拷貝對象就會觸發一次 Full GC

    • 并發標記結束以后,老年代中百分百為垃圾的內存分段被回收了,部分為垃圾的內存分段被計算了出來。默認情況下,這些老年代的內存分段會分8次(可以通過-XX:G1MixedGCCountTarget設置)被回收
    • 混合回收的回收集(Collection Set)包括八分之一的老年代內存分段,Eden區 內存分段,Survivor區內存分段。 混合回收的算法和年輕代回收的算法完全一樣,只是回收集多了老年代的內存分段。具體過程請參考上面的年輕代回收過程。
    • 由于老年代中的內存分段默認分8次回收,G1會優先回收垃圾多的內存分段。垃圾占內存分段比例越高的,越會被先回收。并且有一個閾值會決定內存分段是否被回收,-XX:G1MixedGCLiveThresholdPercent,默認為65%,意思是垃圾占內存分段比例要達到65%才會被回收。如果垃圾占比太低,意味著存活的對象占比高,在復制的時候會花費更多的時間
    • 混合回收并不一定 要進行8次。有一個閾值**-XX :G1HeapWastePercent**,默認值為10%,意思是允許整個堆內存中有10%的空間被浪費,意味著如果發現可以回收的垃圾占堆內存的比例低于10%,則不再進行混合回收。因為GC會花費很多的時間但是回收到的內存卻很少

    5.4 Full GC

    • 特點:G1會停止應用程序的執行(Stop-The-World) ,使用單線程的內存回收算法進行垃圾回收,性能會非常差,應用程序停頓時間會很長。
    • 導致 G1 Full GC 的原因可能有兩個: .
      • 回收時,沒有足夠的 to-space 來存放晉升對象
      • 并發處理過程沒完成空間就耗盡

    總結

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

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。