JVM—GC垃圾回收器總結

来源:https://www.cnblogs.com/Andya/archive/2020/03/08/12445429.html
-Advertisement-
Play Games

本文主要介紹了JVM—GC垃圾回收器,並對其進行了總結。主要包含了Serial收集器、ParNew收集器、Parallel Scavenge收集器、Servial Old收集器、Parallel Old收集器、CMS收集器、G1收集器。 ...


收集演算法(標記-清理、複製、標記-整理、分代收集)是記憶體回收的方法論,垃圾收集器就是記憶體回收的具體實現。

主要有7個gc器,如下圖。gc器

1 Serial收集器

1.1 介紹

Serial收集器是單線程的收集器。
單線程:1.不僅僅說明它只會使用一個CPU或一條收集線程去完成垃圾收集工作,2.且在垃圾收集時,必須暫停其他所有的工作線程,直到它收集結束。
Stop the world:是VM在後臺自動發起和自動完成的,在用戶不可見情況下把用戶正常工作的線程全部停掉。

1.2 缺點:

由於Stop The World,給用戶帶來不良體驗,比如,電腦每運行一段時間就會暫停響應幾分鐘來處理垃圾收集。

1.3 優點

1)簡單而高效(與其他收集器的單線程比);
2)對於限定單個CPU的環境來說,Serial收集器由於沒有線程交互的開銷,專心做垃圾收集自然可以獲得最高的單線程收集效率。

1.4 應用場景

1)VM運行在Client模式下的預設新生代收集器;
2)在用戶的桌面應用場景中,停頓時間完全可以控制在幾十毫秒最多一百多毫秒以內,不頻繁發生,是可接受的

1.5 Serial/Serial Old收集器運行示意圖

Serial/Serial Old收集器

2 ParNew收集器

2.1 介紹

ParNew收集器是Serial收集器多線程版本(是GC線程的多線程,並行)。
並行:Parallel指多條垃圾收集線程並行工作,但此時用戶線程仍然處於等待狀態(多個處理器同時處理多條指令);
併發:Concurrent指用戶線程與垃圾收集線程同時執行(但並不一定是並行的,可能交替執行),用戶程式在繼續運行,而垃圾收集程式運行於另一個CPU上(同一時刻只能有一條指令執行,多個進程指令是交替執行)。

2.2 缺點

在單CPU的環境中絕對不會有比Serial收集器更好的效果,甚至存線上程交互的開銷。

2.3 優點

1)除了Serial收集器外,只有ParNew收集器能與CMS收集器配合工作。
2)CMS(Concurrent Mark Sweep)第一次實現讓垃圾收集線程與用戶線程(基本上)同時工作。

2.4 應用場景

運行在Server模式下的VM首選新生代收集器。

2.5 ParNew/Serial Old收集器運行示意圖

ParNew/Serial Old收集器

2.6 參數控制

• 使用-XX:+UseConcMarkSweepGC選項後預設新生代收集器為ParNew收集器;
• 使用-XX:+UseParNewGC選項強制指定使用ParNew收集器;
• 使用-XX:ParallelGCThreads參數限制垃圾收集的線程數;

3 Parallel Scavenge收集器

3.1 介紹

1)Parallel Scavenge收集器是一個新生代收集器,使用複製演算法的收集器,並行的多線程收集器。更關註吞吐量。
2)吞吐量:CPU用於運行用戶代碼的時間與cpu總消耗時間的比值,即
吞吐量計算公式如虛擬機總共運行100分鐘,垃圾收集花費1分鐘,則吞吐量是99%;吞吐量高效率利用CPU時間,儘快完成程式的運算任務,主要適合後臺運算而不需要太多交互的任務。
3)停頓時間:如CMS等收集器關註點儘可能縮短垃圾收集時用戶線程的停頓時間,停頓時間越短就越適合需要與用戶交互的程式,良好的響應速度可以提升用戶體驗(適合交互)

3.2 參數控制

1)用戶精確控制吞吐量
• 使用-XX:MaxGCPauseMillis參數:控制最大垃圾收集停頓時間
• 使用-XX:GCTimeRatio參數:直接設置吞吐量大小
• 使用-XX:+UseAdaptiveSizePolicy開關參數:GC自適應的調節策略
2)MaxGCPauseMillis參數允許的值是一個大於0的毫秒數,收集器儘可能保證記憶體回收時間不超過設定值。
GC停頓時間縮短犧牲吞吐量和新生代空間——若將MaxGCPauseMillis該值調小帶來的問題:系統把新生代調小一些,收集發生更頻繁一些,吞吐量下降。
GCTimeRatio參數值是一個大於0且小於100的整數,即垃圾收集時間占總時間的比率,相當於吞吐量的倒數。如設置為19,則最大GC時間占1/(1+19)=5%,預設值為99.則最大允許1/(1+99)=1%的垃圾收集時間。
UseAdaptiveSizePolicy開關參數:VM會根據當前系統的運行情況收集性能監控信息,動態調整這些參數以提供最合適的停頓時間或最大吞吐量。自適應調節策略是Parallel Scavenge收集器與ParNew收集器的重要區別。

3.3 應用場景

主要適合後臺運算而不需要太多交互的任務

4 Serial Old收集器

4.1 介紹

Serial Old收集器是Serial收集器的老年代版本,是一個單線程收集器,使用“標記-整理”演算法。

4.2 應用場景

1)主要給Client模式下的VM使用。
2)若在Server模式下用,兩大用途:1.在JDK1.5及之前的版本中與Parallel Scavenge收集器搭配使用;2.作為CMS收集器備選,併在Concurrent Mode Failure時使用。

4.3 Serial/Serial Old收集器運行示意圖

Serial/Serial Old收集器

5 Parallel Old收集器

5.1 介紹

Parallel Old是Parallel Scavenge收集器的老年代版本,是一個多線程收集器,使用“標記-整理”演算法。在JDK1.6開始提供。

5.2 應用場景

註重吞吐量以及CPU資源敏感的場合,優先考慮Parallel Scavenge + Parallel Old收集器。適合吞吐量優先。

5.3 Parallel Scavenge /Parallel Old收集器運行示意圖

Parallel Scavenge /Parallel Old收集器

6 CMS收集器

6.1 介紹

CMS收集器(Concurrent Mark Sweep)是一種以獲取最短回收停頓時間為目標的收集器,是基於“標記-清除”演算法。

6.2 CMS的整個過程有4個步驟

初始標記——併發標記——重新標記——併發清除

初始標記:CMS initial mark僅僅是標記一下GC Roots能直接關聯的對象,速度快;需要stop the world
併發標記:CMS concurrent mark是進行GC Roots Tracing的過程;
重新標記:CMS remark是修正併發標記期間因用戶程式繼續運作而導致標記產生變動的那一部分對象的標記記錄,停頓時間比初始標記長,比併發標記短;需要stop the world
併發清除:CMS concurrent sweep,清除演算法會在收集結束時產生大量空間碎片,有可能導致沒有足夠大的連續空間來分配當前對象而觸發一次Full GC。

6.3 缺點

1)CMS收集器對CPU資源非常敏感;
2)CMS收集器無法處理浮動垃圾,可能出現"Concurrent Mode Failure"失敗(備選用Serial Old)而導致另一次Full GC的產生;
3)CMS是一款基於“標記-清除”演算法的收集器,在收集結束後會產生大量空間碎片。
缺點具體分析
1)對CPU資源敏感:在併發階段會占用一部分線程而導致應用程式變慢,總吞吐量降低;(解決方法是“增量式併發收集器”,但不提倡使用,i-CMS收集器是與單CPU年代PC機操作系統使用搶占式模擬多任務機制的思想,在併發標記、清理的時候讓GC線程、用戶線程交替執行,儘量減少GC線程的獨占資源的時間)
2)無法處理浮動垃圾:CMS併發清理階段用戶線程還在運行,會產生新的垃圾,這部分垃圾出現在標記過程之後,CMS無法在當次收集中處理它們,只好留到下一次GC時再處理。CMS需要預留一部分提供併發收集時的程式運行使用,CMS收集時老年代不能填滿再收集。
3)收集後產生大量空間碎片:“標記-清除”演算法的缺點,解決方案是使用-XX:+UseCMSCompactAtFullCollection和-XX:CMSFullGCsBeforeCompaction參數

6.4 優點

併發收集;低停頓(併發低停頓收集器)

6.5 應用場景

在互聯網站或者B/S系統的服務端上,重視服務的響應速度,希望系統停頓時間最短,給用戶帶來較好的體驗。

6.6 參數控制

  • 使用-XX:CMSInitiatingOccupancyFraction參數:提高觸發老年代CMS垃圾回收的百分比;
  • 使用-XX:+UseCMSCompactAtFullCollection開關參數:預設開啟,用於CMS收集器要進行Full GC時開啟記憶體碎片合併整理過程,非併發的過程;
  • 使用-XX:CMSFullGCsBeforeCompaction參數:用於設置執行多少次不壓縮的Full GC後,緊接著一次帶壓縮的(預設為0,表示每次進入Full GC時就進行碎片整理)

6.7 CMS收集器運行時示意圖

CMS收集器工作流程

7 G1收集器

7.1 介紹

G1(Garbage-First)收集器是一款面向服務端應用的垃圾收集器,為了代替JDK1.5中發佈的CMS收集器。將整個Java堆劃分為多個大小相等的獨立區域。####(Region),保留新生代和老年代概念,但不再是物理隔離,是一部分Region的集合(不需要連續)。

7.2 優點

併發與並行、分代收集、空間整合、可預測的停頓

• 併發與並行:G1能充分利用多CPU、多核環境下的硬體優勢,使用多個CPU縮短storp-the-world停頓時間;G1可通過併發的方式使得java程式運行;
• 分代收集:可以獨立管理整個GC堆,採用不同的方式處理新創建的對象和已經存活一段時間、熬過多次GC的舊對象以獲取更好的收集效果;
• 空間整合:整體上基於“標記-整理”演算法,局部(兩個Region之間)基於“複製”演算法,G1運行期間不會產生記憶體空間碎片,收集後能提供規整的可用記憶體,有利於程式長時間運行,分配大對象時不會因為無法獲得連續記憶體空間而提前觸發下一次GC;
• 可預測的停頓:相比於CMS的另一優勢,能讓使用者明確指定在一個長度為M毫秒的時間片段內,消耗在垃圾收集上的時間不得超過N毫秒。因為可以有計劃地避免在整個java堆上進行全區域的垃圾收集。G1跟蹤各個Region內垃圾堆積的價值大小(回收所獲得的空間大小+回收所需時間的經驗值),在後臺維護一個優先列表,根據允許的收集時間,回收價值最大的Region(Garbage-First的由來)。

7.3 G1將記憶體“化整為零”的思路

Region之間的對象引用以及其他收集器中的新生代與老年代之間的對象引用,VM都是通過Remember Set來避免全堆掃描。G1中每個Region中都有一個與之對應的Remember Set:
1)VM發現程式對Reference類型的數據進行寫操作時,會產生一個Write Barrier暫時中斷寫操作;
2)檢查Reference引用的對象是否處於不同的Region之中;如果是,便通過CardTable把相關引用信息記錄到被引用對象所屬的Region的Remember Set之中;
3)當進行記憶體回收時,在GC根節點的枚舉範圍中加入Remember Set即可保證不對全堆掃描;

(4)G1收集器運作的步驟:

初始標記——併發標記——最終標記——篩選回收

  • 初始標記:initial marking,標記一下GC Roots能直接關聯的對象,並且修改TAMS(Next Top at Mark Start)的值,讓下一階段用戶程式併發運行時,能在正確可用的Region中創建新對象,需要停頓線程,耗時短;
  • 併發標記:concurrent marking,從GC Root開始對堆中對象進行可達性分析,找出存活的對象,這階段耗時長,但可與用戶程式併發執行;
  • 最終標記:final marking,修正在併發標記期間因用戶程式繼續運作而導致標記產生變動的那一部分標記記錄,對象變化記錄存線上程Remember Set Logs中,然後把這些數據合併到Remember Set中,該階段停頓線程,但是可並行執行;
  • 篩選回收:live data counting and evacuation,對各個Region的回收價值和成本進行排序,根據用戶所期望的GC停頓時間來指定回收計劃。

    (5)G1收集器運行示意圖:

    G1收集器工作流程

    8 安全點

    8.1 介紹

    1)Safepoint:在HotSpot的實現中,使用一組稱為OopMap的數據結構,在類載入完成的時候,HotSpot把對象帶內什麼偏移量上是什麼類型的數據都計算出來,在JIT編譯過程中,也會在特定的位置記錄下棧和寄存器中哪些位置是引用,這些特定的位置就是安全點。
    2)程式執行時並非在所有的地方都能停頓下來開始GC,只有到達安全點時才能暫停。
    3)安全點的選定:標準是“是否具有讓程式長時間執行的特征”,不能太少以至於讓GC等待時間太長,也不能過於頻繁以至於過分增大運行時的負荷。

8.2 安全點的停頓

如何在GC發生時讓所有線程都“跑”到最近的安全點停頓?兩種方案:搶先式中斷和主動式中斷。

搶先式中斷:不需要線程的執行代碼主動去配合,在GC發生時,首先把所有線程全部中斷,如果發現有線程中斷的地方不在安全點上,就恢複線程,讓它“跑”到安全點上。(現在幾乎不用)
主動式中斷:當GC需要中斷線程的時候,不直接對線程操作,僅僅設置一個標誌,各個線程執行時主動去輪詢這個標誌,發現中斷標誌為真時就自己中斷掛起。輪詢標誌的地方和安全點是重合的,另外再加上創建對象需要分配記憶體的地方。

8.3 安全點的作用

1)safepoint保證程式執行時,在不太長的時間內就會遇到可進入的GC的safepoint。
2)若程式不執行,則沒有分配CPU時間,如線程處於Sleep或Blocked狀態,無法響應JVM的中斷請求,此時需要安全區域解決,在一段代碼片段中,引用關係不會發生變化,在這個區域中的任意地方開始GC都是安全的。

9 垃圾收集器的參數總結

9.1 GC器的參數

GC參數

9.2 GC器的使用

GC器配合使用

主要參考了《深入理解Java虛擬機》這本書,這本書是真心好,值得一讀。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 折半查找的應用 public static void main(String[] args) { int[] arr = {4,6,6,7,8,9,10}; System.out.println(getIndexOf(arr,5)); } public static int getIndexOf(i ...
  • public static void main(String[] args) { int[] arr = {0,1,2,3,4,5,6,7,8,9,10}; System.out.println(halfSearch_2(arr,5)); } public static int halfSearch ...
  • Python 第三方庫國內鏡像下載地址 由於 Python 伺服器在國外,因此使用 pip 安裝第三方模塊或者庫的時候,下載速度特別慢,經常出現如下報錯: $ socket.timeout: The read operation timed out 為提升下載速度,可以使用國內鏡像下載,常用的國內鏡 ...
  • 本文源碼: "GitHub·點這裡" || "GitEE·點這裡" 一、String類簡介 1、基礎簡介 字元串是一個特殊的數據類型,屬於引用類型。String類在Java中使用關鍵字final修飾,所以這個類是不可以繼承擴展和修改它的方法。String類用處極廣泛,在對String對象進行初始化時 ...
  • 緣由 這個起因是昨晚群里有人在討論怎麼把字元串轉成 方法最佳,討論到最後變成哪種方法效率最優了。畢竟這代碼是要在MCU上面跑的,要同時考慮到時間和空間的最優解。 當然討論的是有結果的,具體實現的方法和代碼在下麵展示。 char數組轉16進位HEX串 例子: 將如下的量 轉成 這樣的結果 這個其實很簡 ...
  • 只要有一輪沒有發生交換,說明數據的順序已經排好,沒有必要繼續進行迴圈下去了。 public static void main(String[] args) { int[] arr = {1,3,5,7,9,2,4,6,8,0}; sort(arr); } public static void sor ...
  • 1,什麼是字元串? 所謂字元串本質上就是以'\0作為'結尾的特殊字元數組; 2,定義字元串的過程中有哪些註意點 由於字元串本質上其實就是以'\0作為'結尾的特殊字元數組,所以定義字元串時,必須保證字元串存儲的最後一個元素為'\0'。 當我們沒有給定字元串具體長度時,我們通過這種方式:char 字元串 ...
  • 如果元素已經在該在的位置上就不需要再交換位置了。 public static void main(String[] args) { int[] arr = {1,3,5,7,9,2,4,6,8,0}; sort(arr); } public static void sort(int[] arr){ ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...