深入理解JVM——虛擬機GC

来源:https://www.cnblogs.com/liangf27/archive/2018/12/07/10085854.html
-Advertisement-
Play Games

對象是否存活 Java的GC基於可達性分析演算法(Python用引用計數法),通過可達性分析來判定對象是否存活。這個演算法的基本思想是通過一系列"GC Roots"的對象作為起始點,從這些節點開始向下搜索,搜索所走過的路徑稱為引用鏈,當一個對象到GC Roots沒有任何引用鏈相連時(圖論稱之為不可達), ...


對象是否存活

Java的GC基於可達性分析演算法(Python用引用計數法),通過可達性分析來判定對象是否存活。這個演算法的基本思想是通過一系列"GC Roots"的對象作為起始點,從這些節點開始向下搜索,搜索所走過的路徑稱為引用鏈,當一個對象到GC Roots沒有任何引用鏈相連時(圖論稱之為不可達),則證明此對象是不可用的。

無論引用計數法,還是可達性分析都離不開“引用”的概念。Java將引用分為四種(強引用、軟引用,弱引用,虛引用),這四種引用強度依次逐漸減弱。

  • strong reference強引用,垃圾收集器永遠不會回收存在強引用的對象。(如Object obj = new object()就是一個強引用)

  • soft reference軟引用,描述一些還有用但是並非必須的對象。系統將要發生記憶體溢出異常之前,將會把這些軟引用對象列入回收範圍中進行二次回收。如果這次回收之後還是不夠記憶體,才會拋出記憶體溢出異常。

  • weak reference弱引用,也是用來描述非必須對象的,但是它的強度更弱。被弱引用的對象只能活到下一次GC發生之前。當GC發生,無論當前記憶體是否充足都會回收弱引用對象。

  • phantom reference虛引用(幽靈引用),是最弱的一種引用關係。為一個對象設置虛引用關聯的唯一目的就是能在這個對象被收集器回收時收到一個系統通知。

在可達性演算法中不可達的對象,不會直接死亡,如果它還沒有執行finalize方法,虛擬機將在一個優先順序很低的線程中觸發它的finalize方法(不保證完成),如果此時對象又將自己關聯到引用鏈上,那麼GC將把它移出“即將回收”的集合。

由於finalize方法只會被執行一次,所以這個“自救”過程也只會經歷一次。

垃圾回收方法

1、標記清除法

首先標記所有需要回收的對象,然後統一回收所有要回收的對象。方法簡單,但是效率不高,並且產生了很多記憶體碎片。

2、複製演算法

將記憶體分為大小相等的兩塊,每次只使用一塊。當一塊的記憶體用完了,就將還存活的對象複製到另一塊記憶體上,然後把使用過的那一半記憶體空間一次性清理掉。這樣再分配記憶體時只需要移動堆頂指針,實現簡單,運行高效。但是代價是實際可用記憶體縮小了一半,實在太高。

因為新生代大部分對象都是”朝生夕死“,所以虛擬機將記憶體分為1個Eden和2個Survivor空間,大小比例預設為8:1:1。當回收時,將Eden和Survivor中還存活著的對象複製到另一個Survivor空間上,然後清理掉Eden和剛纔用過的Survivor空間。這樣子就只需要犧牲10%的新生代記憶體。

分配擔保:因為存在1個Survivor空間存放不了Eden和另一個Survivor空間的對象的情況,此時那些存活的對象由於無法放入該Survivor空間,將直接進入老年代。)

3、標記-整理演算法

老年代對象存活率高,複製演算法在這時候效率很低,而且老年代沒有額外空間做分配擔保,所以不適用。根據這種特點,有人提出了標記-整理演算法。

首先標記所有要回收的對象,然後所有存活的對象都向一端移動,然後直接清理邊界以外的記憶體。

4、分代收集演算法

前面三個垃圾回收演算法都算是鋪墊,現在商業虛擬機的垃圾收集都採用”分代收集“。將Java堆分成新生代和老年代,新生代中每次GC有大量對象死去,只有少量存活,所以採用複製演算法;老年代中對象存活率高,沒有額外空間進行分配擔保,就採用標記-清除或者標記-整理演算法。

垃圾收集器

 

新生代:serial收集器

單線程,必須暫停其他所有工作線程(Stop The World),直到它收集結束。STW難以接受,但是簡單高效。

新生代:parNew收集器

serial的多線程版本。server模式下首選,因為它可以和cms配合使用。

新生代:parallel scavenge收集器

專註於達到可控制吞吐量的收集器,主要適合後臺運算而不用太多交互的任務。

老年代:serial old收集器

serial的老年代版本,單線程。使用標記-整理演算法。

 

老年代:parallel old收集器

parallel scavenge的老年代版本。使用標記-整理演算法。

 

老年代:cms收集器

經歷四個階段:

  • 初始標記:需要STW,僅僅標記一下GC Roots能直接關聯的對象,所以很快。

  • 併發標記:進行GC Roots Tracing

  • 重新標記:需要STW,修正併發標記期間因程式運行導致標記產生變動的那一部分對象的標記記錄,時間比初始標記長,但是遠比併發標記短

  • 併發清除:清除對象

由於耗時最長的併發標記和併發清除過程,收集器線程都可以和用戶線程一起工作,所以總體來說cms收集器的記憶體回收過程是和用戶線程一起併發執行的,停頓很短。

缺點:cpu資源敏感,特別是cpu核數較少時;無法處理浮動垃圾;cms基於標記-清除演算法,容易產生大量記憶體碎片。

G1收集器

最新的收集器,性能優秀,但是太複雜不再贅述。

記憶體分配和回收策略

  • 對象優先在Eden分配,如果啟動了TLAB,將按照線程優先在TLAB上分配。

  • 當Eden不夠空間時,虛擬機發起一次Minor GC(新生代GC)

  • 大對象直接進入老年代

  • 長期存活的對象將進入老年代(存活一次GC age+1,預設age 15時進入老年代)

  • Survivor空間中相同年齡所有年齡大小 的總和大於Survivor空間的一半 時,年齡大於等於該年齡的對象可以直接進入老年代

  • Minor GC時,虛擬機會檢查老年代的剩餘空間是否大於新生代對象總大小or歷次晉升的平均大小,如果是那麼就會進行Minor GC,否則認為老年代無法提供分配擔保,進行Full GC。


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

-Advertisement-
Play Games
更多相關文章
  • 前言 Java多線程分類中寫了21篇多線程的文章,21篇文章的內容很多,個人認為,學習,內容越多、越雜的知識,越需要進行深刻的總結,這樣才能記憶深刻,將知識變成自己的。這篇文章主要是對多線程的問題進行總結的,因此羅列了40個多線程的問題。 這些多線程的問題,有些來源於各大網站、有些來源於自己的思考。 ...
  • 給定數據利用神經網路演算法模型進行計算,利用FP、BP演算法,求得模型最優值。 神經網路初步學習使用。 ...
  • //接受數據請求public function client($pz){ //參數1是:網路協議, //AF_INET: IPv4 網路協議。TCP 和 UDP 都可使用此協議。一般都用這個,你懂的。 //AF_INET6: IPv6 網路協議。TCP 和 UDP 都可使用此協議。 //AF_UNI ...
  • 1.首先感謝同事 2.之前一直在做angularjs的項目,目前vue火熱,所以自己搭建了一個的vue框架,在此作為記錄 vue+vux-ui這裡就不介紹了,有很多博客都寫的很詳細了。 下麵簡單記錄下axios 和 mock 1.axios <1> 安裝axios <2> 使用axios 1.因為有 ...
  • 適配器模式(Adapter Pattern)又叫做變壓器模式,變壓器把一種電壓變換為另一種電壓。 定義: 將一個類的介面變換成客戶端所期待的另一種介面,從而使原本因介面不匹配而無法一起工作的兩個類能夠在一起工作。 適配器模式就是將一個介面或類轉換成其它的介面或類,適配器相當於一個包裝器,類圖如下所示 ...
  • 用CEF4Delphi取網頁元素時碰到ElementInnerText里含有"&nbsp;" 比如網頁源碼里是"內容&nbsp;"取出來顯示就變成"內容?" 搜索大部分是說把"&nbsp;"替換成其它字元即可 但實際操作怎麼也替換不了,就算變數為AnsiString也不行 最後用了以下方法解決 參考 ...
  • GitHub 上有一個名為《What the f*ck Python!》的項目,這個有趣的項目意在收集 Python 中那些難以理解和反人類直覺的例子以及鮮為人知的功能特性, 並嘗試討論這些現象背後真正的原理! ...
  • 1.單引號和轉義引導 2.拼接字元串 3.格式化字元串 4.常用方法 #去掉空格和特殊符號 #字元串的搜索和替換 #字元串的測試和替換函數 #字元串的分割 #string模塊 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...