【JVM】Java虛擬機(二)——垃圾回收

目錄

一、如何判斷對象可以回收

(一)引用計數法

(二)可達性分析算法

二、垃圾回收算法

(一)標記清除

(二)標記整理

(三)復制

(四)分代垃圾回收

(五)相關 VM 參數

三、垃圾回收器

(一)串行(Serial)

(二)吞吐量優先

(三)響應時間優先

(四)G1

核心特點

(一)G1 垃圾回收階段

(二)核心階段詳解

(1) 年輕代GC(Young GC)

(2) 并發標記周期

(3) 混合回收(Mixed GC)

(三)G1關鍵調優參數

基礎配置

區域配置

并發周期控制

四、垃圾回收調優

(一)調優領域

(二)確定目標

(三)最快的 GC

(四)新生代調優

(五)老年代調優


一、如何判斷對象可以回收

(一)引用計數法

給對象中添加一個引用計數器:

  • 每當有一個地方引用它,計數器就加 1;
  • 當引用失效,計數器就減 1;
  • 任何時候計數器為 0 的對象就是不可能再被使用的。

這個方法實現簡單,效率高,但是目前主流的虛擬機中并沒有選擇這個算法來管理內存,其最主要的原因是它很難解決對象之間循環引用的問題。

所謂對象之間的相互引用問題,如下面代碼所示:除了對象 objAobjB 相互引用著對方之外,這兩個對象之間再無任何引用。但是他們因為互相引用對方,導致它們的引用計數器都不為 0,于是引用計數算法無法通知 GC 回收器回收他們。

public class ReferenceCountingGc {Object instance = null;public static void main(String[] args) {ReferenceCountingGc objA = new ReferenceCountingGc();ReferenceCountingGc objB = new ReferenceCountingGc();objA.instance = objB;objB.instance = objA;objA = null;objB = null;}
}

(二)可達性分析算法


Java通過GC Roots對象作為起點,向下搜索引用鏈。若對象與GC Roots無引用鏈相連,則判定為可回收。


GC Roots包括

  • 虛擬機棧中引用的對象(如局部變量)

  • 方法區中類靜態屬性引用的對象

  • 方法區中常量引用的對象

  • 本地方法棧中JNI引用的對象

  • 同步鎖持有的對象

  • 活躍線程對象

  • 引用類型與回收策略

    引用類型回收條件示例
    強引用永不回收(除非顯式置為nullObject obj = new Object()
    軟引用(Soft)內存不足時回收SoftReference<Object> ref
    弱引用(Weak)下次GC必然回收WeakReference<Object> ref
    虛引用(Phantom)僅用于回收跟蹤PhantomReference<Object> ref
  • 對象死亡過程

1. 強引用

  • 只有所有 GC Roots 對象都不通過【強引用】引用該對象,該對象才能被垃圾回收

2. 軟引用(SoftReference)

  • 僅有軟引用引用該對象時,在垃圾回收后,內存仍不足時會再次出發垃圾回收,回收軟引用對象
  • 可以配合引用隊列來釋放軟引用自身

3. 弱引用(WeakReference)

  • 僅有弱引用引用該對象時,在垃圾回收時,無論內存是否充足,都會回收弱引用對象
  • 可以配合引用隊列來釋放弱引用自身

4. 虛引用(PhantomReference)

  • 必須配合引用隊列使用,主要配合 ByteBuffer 使用,被引用對象回收時,會將虛引用入隊, 由 Reference Handler 線程調用虛引用相關方法釋放直接內存

5. 終結器引用(FinalReference)

  • 無需手動編碼,但其內部配合引用隊列使用,在垃圾回收時,終結器引用入隊(被引用對象 暫時沒有被回收),再由 Finalizer 線程通過終結器引用找到被引用對象并調用它的 finalize 方法,第二次 GC 時才能回收被引用對象

二、垃圾回收算法

(一)標記清除

定義: Mark Sweep

  • 速度較快
  • 會造成內存碎片

(二)標記整理

定義:Mark Compact

  • 速度慢
  • 沒有內存碎片

(三)復制

定義:Copy

  • 不會有內存碎片
  • 需要占用雙倍內存空間

(四)分代垃圾回收

  • 年輕代(Young Generation)

    • 對象分配:新對象在Eden區創建

    • 回收算法:復制算法(Minor GC)

    • 過程

      1. Eden(伊甸園) + S0(From)存活對象復制到S1(To)

      2. 清空Eden(伊甸園)和S0(From)

      3. S0(From)與S1(To)角色交換

    • 晉升條件:對象年齡(經歷GC次數)達到閾值(默認15),或Survivor區空間不足

  • 老年代(Old Generation)

    • 存放長期存活對象

    • 回收算法:標記-清除或標記-整理(Major GC/Full GC)

    • 觸發條件:年輕代晉升失敗或空間不足

  • 對象首先分配在伊甸園區域
  • 新生代空間不足時,觸發 Minor GC,伊甸園和 From 存活的對象使用copy復制到 To 中,存活的對象年齡加1并且交換 From 和 To
  • Minor GC 會引發 Stop The World,暫停其它用戶的線程,等垃圾回收結束,用戶線程才恢復運行
  • 當對象壽命超過閾值時,會晉升至老年代,最大壽命是15(4bit)
  • 當老年代空間不足,會先嘗試觸發 Minor GC,如果之后空間仍不足,那么觸發 Full GC,STW的時間更長

算法原理優點缺點
標記-清除1. 標記所有活動對象
2. 清除未標記對象
實現簡單內存碎片化,分配效率低
復制內存分為兩塊,每次使用一塊。GC時將存活對象復制到另一塊,清空當前塊。無碎片,高效內存利用率僅50%
標記-整理1. 標記活動對象
2. 將存活對象向內存一端移動
3. 清理邊界外內存
無碎片,內存利用率高對象移動開銷大
分代收集結合多種算法,按對象生命周期分區管理綜合性能最優(主流方案)實現復雜

(五)相關 VM 參數

含義參數
堆初始大小-Xms
堆最大大小-Xmx 或 -XX:MaxHeapSize=size
新生代大小-Xmn 或 (-XX:NewSize=size + -XX:MaxNewSize=size )
幸存區比例(動態)-XX:InitialSurvivorRatio=ratio 和 -XX:+UseAdaptiveSizePolicy
幸存區比例-XX:SurvivorRatio=ratio
晉升閾值-XX:MaxTenuringThreshold=threshold
晉升詳情-XX:+PrintTenuringDistribution
GC詳情-XX:+PrintGCDetails -verbose:gc
FullGC 前 MinorGC-XX:+ScavengeBeforeFullGC

三、垃圾回收器

1. 串行(Serial)

  • 單線程
  • 堆內存較小,適合個人電腦

2. 吞吐量優先(Parallel Scavenge)

  • 多線程
  • 堆內存較大,多核 cpu
  • 讓單位時間內,STW 的時間最短 0.2 0.2 = 0.4,垃圾回收時間占比最低,這樣就稱吞吐量高

3. 響應時間優先(CMS)

  • 多線程
  • 堆內存較大,多核 cpu
  • 盡可能讓單次 STW 的時間最短 0.1 0.1 0.1 0.1 0.1 = 0.5

(一)串行(Serial)

-XX:+UseSerialGC = Serial + SerialOld

(二)吞吐量優先(Parallel Scavenge)

-XX:+UseParallelGC ~ -XX:+UseParallelOldGC

-XX:+UseAdaptiveSizePolicy

-XX:GCTimeRatio=ratio

-XX:MaxGCPauseMillis=ms

-XX:ParallelGCThreads=n

(三)響應時間優先(CMS)

-XX:+UseConcMarkSweepGC ~ -XX:+UseParNewGC ~ SerialOld

-XX:ParallelGCThreads=n ~ -XX:ConcGCThreads=threads

-XX:CMSInitiatingOccupancyFraction=percent

-XX:+CMSScavengeBeforeRemark

(四)G1

G1 (Garbage-First)?是Java 7引入、Java 9成為默認的垃圾回收器,專為大內存、低延遲場景設計,替代了傳統的CMS回收器。

核心特點

  • 分區模型:將堆劃分為多個等大小的Region(默認約2048個)

  • 分代收集:保留新生代/老年代概念,但物理不連續

  • 可預測停頓:通過-XX:MaxGCPauseMillis設置目標停頓時間

  • 并發標記:與應用程序線程并行工作

  • 混合回收:同時清理新生代和老年代區域

(一)G1 垃圾回收階段

Young Collection

  • 會 STW

Young Collection + CM

  • 在 Young GC 時會進行 GC Root 的初始標記
  • 老年代占用堆空間比例達到閾值時,進行并發標記(不會 STW),由下面的 JVM 參數決定

-XX:InitiatingHeapOccupancyPercent=percent (默認45%)

Mixed Collection

會對 E、S、O 進行全面垃圾回收

  • 最終標記(Remark)會 STW
  • 拷貝存活(Evacuation)會 STW

-XX:MaxGCPauseMillis=ms

(二)核心階段詳解

(1) 年輕代GC(Young GC)
  • 觸發條件:Eden區滿時

  • 過程

    1. STW(Stop-The-World)開始

    2. 構造回收集(Collection Set = Eden + Survivor)

    3. 復制存活對象到新Survivor區

    4. 年齡達到閾值(默認15)的對象晉升老年代

(2) 并發標記周期
  • 觸發條件:老年代占用超過IHOP閾值(默認45%)

  • 階段組成

    • 初始標記(STW):伴隨Young GC進行

    • 根區域掃描:掃描Survivor區引用

    • 并發標記:標記存活對象(與應用并發)

    • 最終標記(STW):處理SATB緩沖區

    • 清理(STW):統計完全空閑Region

(3) 混合回收(Mixed GC)
  • 回收包含年輕代Region +?高收益的老年代Region

  • 根據垃圾比例排序Region(Garbage-First原則)

  • 多次執行直到滿足回收目標

(三)G1關鍵調優參數

基礎配置
參數默認值說明
-XX:+UseG1GC-啟用G1回收器
-Xms?/?-Xmx-堆初始/最大大小(建議設相同值)
-XX:MaxGCPauseMillis200ms目標最大停頓時間
區域配置
參數默認值說明
-XX:G1HeapRegionSize1-32MBRegion大小(2的冪次)
-XX:G1NewSizePercent5%新生代最小占比
-XX:G1MaxNewSizePercent60%新生代最大占比
并發周期控制
參數默認值說明
-XX:InitiatingHeapOccupancyPercent45%IHOP閾值(觸發并發標記)
-XX:G1MixedGCLiveThresholdPercent85%Region存活對象低于此值才回收
-XX:G1HeapWastePercent5%可回收垃圾占比閾值(停止Mixed GC)

四、垃圾回收調優

(一)調優領域

  1. 內存
  2. 鎖競爭
  3. cpu
  4. 占用 io

(二)確定目標

  • 【低延遲】還是【高吞吐量】,選擇合適的回收器
  • CMS,G1,ZGC
  • ParallelGC
  • Zing

(三)最快的 GC

答案是不發生 GC

查看 FullGC 前后的內存占用,考慮下面幾個問題

數據是不是太多?

  • resultSet = statement.executeQuery("select * from 大表 limit n")

數據表示是否太臃腫?

  • 對象圖
  • 對象大小 16 Integer 24 int 4

是否存在內存泄漏?

  • static Map map =
  • 第三方緩存實現

(四)新生代調優

  • 新生代的特點

    • 所有的 new 操作的內存分配非常廉價
      • TLAB thread - local allocation buffer
    • 死亡對象的回收代價是零
    • 大部分對象用過即死
    • Minor GC 的時間遠遠低于 Full GC
  • 越大越好嗎?

  • 新生代能容納所有【并發量*(請求 - 響應)】的數據

  • 幸存區大到能保留【當前活躍對象 + 需要晉升對象】

  • 晉升閾值配置得當,讓長時間存活對象盡快晉升

    • -XX:MaxTenuringThreshold = threshold
    • -XX:+PrintTenuringDistribution
    Desired survivor size 48286924 bytes, new threshold 10 (max 10)age 1: 28992024 bytes, 28992024 total
    age 2: 1366864 bytes, 30358888 total
    age 3: 1425912 bytes, 31784800 total?…

(五)老年代調優

以 CMS 為例

  • CMS 的老年代內存越大越好
  • 先嘗試不做調優,如果沒有 Full GC 那么已經…,否則先嘗試調優新生代
  • 觀察發生 Full GC 時老年代內存占用,將老年代內存預設調大 1/4 ~ 1/3
    • -XX:CMSInitiatingOccupancyFraction=percent

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

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

相關文章

Android 實現可拖動的ImageView

Android 實現可拖動的ImageView 代碼實現&#xff1a; public class DraggableImageView extends AppCompatImageView {private float lastTouchX;private float lastTouchY;public DraggableImageView(Context context) {super(context);init();}public DraggableImageView(C…

微信小程序中wxs

一、先新建wxs文件subutil.wxs 1、寫過濾器 //return class var isClass function(val) {if (val 0) {return grid-item} else if (val 1) {return temperature-error-slot} else if (val 2) {return chargingCycles-error-slot} else {return unrecognized-slot} } 2、…

Nginx攻略

&#x1f916; 作者簡介&#xff1a;水煮白菜王&#xff0c;一位前端勸退師 &#x1f47b; &#x1f440; 文章專欄&#xff1a; 前端專欄 &#xff0c;記錄一下平時在博客寫作中&#xff0c;總結出的一些開發技巧和知識歸納總結?。 感謝支持&#x1f495;&#x1f495;&#…

常見系統設計

秒殺系統 前端層&#xff1a; 靜態資源緩存&#xff1a;通過CDN緩存商品圖片、頁面靜態HTML&#xff0c;減少回源請求。 請求合并&#xff1a;合并用戶頻繁刷新的請求&#xff08;如10秒內僅允許一次真實請求&#xff09;。 端側限流&#xff1a;通過JS或APP端限制用戶高頻點擊…

git撤回commit

最常見的幾種撤回方式&#xff1a; 目標使用命令是否保留修改撤回最后一次 commit&#xff0c;但保留代碼修改git reset --soft HEAD~1? 保留撤回最后一次 commit&#xff0c;并丟棄修改git reset --hard HEAD~1? 丟棄撤回某個 commit&#xff0c;但保留后續提交git revert …

docker 安裝運行mysql8.4.4

先前一直使用mysql5.7&#xff0c;最新公司新項目&#xff0c;無意翻閱看下5.x版本mysql官方已經不再支持&#xff0c;于是準備選用MySQL8&#xff0c;官方8.4版本是個長期支持版本&#xff0c;選則最新版本8.4.4&#xff0c;如下是MySQL官方對版本支持計劃 MySQL版本下載查看地…

[java八股文][MySQL面試篇]索引

索引是什么&#xff1f;有什么好處&#xff1f; 索引類似于書籍的目錄&#xff0c;可以減少掃描的數據量&#xff0c;提高查詢效率。 如果查詢的時候&#xff0c;沒有用到索引就會全表掃描&#xff0c;這時候查詢的時間復雜度是On如果用到了索引&#xff0c;那么查詢的時候&a…

低代碼平臺的版本管理深度解析

引言 在當今快速發展的軟件開發領域&#xff0c;低代碼平臺憑借其可視化界面和拖拽功能&#xff0c;極大地減少了手動編碼的工作量&#xff0c;顯著提高了開發效率和質量。它提供了豐富的預構建模塊、組件和服務&#xff0c;讓開發者能夠根據業務需求和邏輯進行組合與配置&…

Springboot項目由JDK8升級至JDK17全過程教程【文末附源碼】

1. 前言 最近一直想把我的開源項目maple-boot升級到jdk17版本&#xff0c;然后接入Spring AI。拖延癥犯了一直拖拖拖&#xff0c;最近時間空閑較多&#xff0c;開始陸續著手升級。 整個升級過程 計劃分為3步。 step1&#xff1a;先將項目升級到jdk17&#xff0c;使用正常ste…

同步與異步:軟件工程中的時空藝術與實踐智慧-以蜻蜓hr人才系統舉例-優雅草卓伊凡

同步與異步&#xff1a;軟件工程中的時空藝術與實踐智慧-以蜻蜓hr人才系統舉例-優雅草卓伊凡 概念解析&#xff1a;時空維度的編程范式 在軟件開發的宇宙中&#xff0c;同步(Synchronous)與異步(Asynchronous)是兩種根本不同的執行模式&#xff0c;它們塑造了程序與時間和空間…

TF-IDF算法的代碼實踐應用——關鍵詞提取、文本分類、信息檢索

回顧&#xff1a;TF-IDF算法詳解與實踐總結 上一篇文章我們深入剖析了TF-IDF的原理與細節&#xff0c;但實踐才是檢驗真理的唯一標準&#xff01;今天&#xff0c;我們將從“紙上談兵”轉向“實戰演練”&#xff1a;通過純Python手寫實現與調用sklearn工具包兩種方式&#xff0…

前端面試寶典---事件循環面試題

瀏覽器進程模型與 JavaScript 執行機制 現代瀏覽器采用多進程架構&#xff0c;包含瀏覽器進程、渲染進程、網絡進程等多個核心進程。每個標簽頁會獨立創建一個渲染進程&#xff0c;負責頁面內容的解析、渲染和執行腳本代碼。 JavaScript 的單線程特性 JavaScript 采用單線程…

postman調用接口報錯401, Unauthorized, Invalid Token. null解決辦法

1、先登錄系統&#xff0c;F12找到token并復制 2、postman里選中Authorization,下拉選中選擇Bearer Token,把復制好的token黏貼到右側輸入框&#xff0c;如下所示&#xff1a; 3、如果是json格式的參數拷貝到Body中&#xff0c;如下所示&#xff1a; 4、 接口調用成功

C++----剖析list

前面學習了vector和string&#xff0c;接下來剖析stl中的list&#xff0c;在數據庫中學習過&#xff0c;list邏輯上是連續的&#xff0c;但是存儲中是分散的&#xff0c;這是與vector這種數組類型不同的地方。所以list中的元素設置為一個結構體&#xff0c;將list設計成雙向的&…

為什么已經有 Nginx 了,還需要服務網關?

在當前微服務架構中&#xff0c;雖然 Nginx 是一個高性能的反向代理和負載均衡服務器&#xff0c;但在實際使用中仍然存在諸多局限性。為了滿足運維效率、功能統一治理以及與微服務生態集成的需求&#xff0c;通常會在 Nginx 和業務服務之間引入一層基于 Java 實現的服務網關&a…

Kendo UI 中,ViewModel、DataSource 和 Grid的關系。Kendo 框架發起 HTTP 請求

Kendo UI 中&#xff0c;ViewModel、DataSource 和 Grid的關系 在 Kendo UI 中&#xff0c;ViewModel、DataSource 和 Grid 是構建動態數據應用的核心組件&#xff0c;三者協同工作實現數據的綁定、管理和展示。 一、三者關系圖解 #mermaid-svg-3lWxu2zWB23wDYEz {font-family…

宇樹開源 Qmini 雙足機器人,可通過 3D 打印動手制作,使用樹莓派作為主控制器

Unitree Qmini 是一款由宇樹科技設計并開源的低成本雙足機器人&#xff0c;開發者可以完全通過 3D 打印進行復刻。Qmini 專為業余愛好者、教育工作者和研究人員設計&#xff0c;使用戶能夠快速上手&#xff0c;并以類似樂高的模塊化方式組裝自己的機器人。該項目為機器人技術提…

解決華為云服務器無法ping通github問題

在push代碼到github上的時候&#xff0c;發現顯示22端口無法連接&#xff0c;在已經開放了端口&#xff0c;防火墻關閉的情況下仍然無法連接到GitHub。 發現是服務器和github斷連&#xff0c;選擇 sudo vim /etc/hosts 添加一下代碼 # GitHub Start140.82.121.4 gith…

關于electron-vite koffi 讀取 dll 打包等問題得記錄

koffi const koffi require(‘koffi’) import iconv from ‘iconv-lite’;const libPath path.resolve(__dirname, ‘…/…/resources/dll/sss.dll’) const yktLib koffi.load(libPath) const ret yktLib.func(‘string sss(string Url, string Data, string OutData)’…

【開發技術】.Net使用FFmpeg視頻特定幀上繪制內容

目錄 一、目的 二、解決方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg調用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 濾鏡來繪制 ROI 三、總結 一、目的 當前市場上有很多目標檢測智能識別的相關算法&#xff0c;當前調用一個醫療行業的AI識別算法后返回…