JVM:併發的可達性分析

来源:https://www.cnblogs.com/feiyu2/archive/2023/04/11/17305928.html
-Advertisement-
Play Games

當前主流編程語言的垃圾收集器基本上都是依靠可達性分析演算法來判定對象是否存活的,可達性分析演算法理論上要求全過程都基於一個能保障一致性的快照中才能夠進行分析,這意味著必須全程凍結用戶線程的運行。 在根節點枚舉這個步驟中,由於 GC Roots 相比起整個 Java 堆中全部的對象畢竟還算是極少數,且在各 ...


當前主流編程語言的垃圾收集器基本上都是依靠可達性分析演算法來判定對象是否存活的,可達性分析演算法理論上要求全過程都基於一個能保障一致性的快照中才能夠進行分析,這意味著必須全程凍結用戶線程的運行。

  • 在根節點枚舉這個步驟中,由於 GC Roots 相比起整個 Java 堆中全部的對象畢竟還算是極少數,且在各種優化技巧(如 OopMap)的加持下,它帶來的停頓已經是非常短暫且相對固定(不隨堆容量而增長) 的了。
  • 可從 GC Roots 再繼續往下遍歷對象圖,這一步驟的停頓時間就必定會與 Java 堆容量直接成正比例關係了:堆越大,存儲的對象越多,對象圖結構越複雜,要標記更多對象而產生的停頓時間自然就更長。

要知道包含 “標記” 階段是所有追蹤式垃圾收集演算法的共同特征,如果這個階段會隨著堆變大而等比例增加停頓時間,其影響就會波及幾乎所有的垃圾收集器,同理可知,如果能夠削減這部分停頓時間的話,那收益也將會是系統性的。

想解決或者降低用戶線程的停頓,就要先搞清楚為什麼必須在一個能保障一致性的快照上才能進行對象圖的遍歷?為了能解釋清楚這個問題,我們引入三色標記(Tri-color Marking)作為工具來輔助推導,把遍歷對象圖過程中遇到的對象,按照 “是否訪問過” 這個條件標記成以下三種顏色:

  • 白色:表示對象尚未被垃圾收集器訪問過。顯然在可達性分析剛剛開始的階段,所有的對象都是白色的,若在分析結束的階段,仍然是白色的對象,即代表不可達。
  • 黑色:表示對象已經被垃圾收集器訪問過,且這個對象的所有引用都已經掃描過。黑色的對象代表已經掃描過,它是安全存活的,如果有其他對象引用指向了黑色對象,無須重新掃描一遍。黑色對象不可能直接(不經過灰色對象) 指向某個白色對象。
  • 灰色:表示對象已經被垃圾收集器訪問過,但這個對象上至少存在一個引用還沒有被掃描過。

關於可達性分析的掃描過程,可以發揮一下想象力,把它看作對象圖上一股以灰色為波峰的波紋從黑向白推進的過程。如果用戶線程此時是凍結的,只有收集器線程在工作,那不會有任何問題。但如果用戶線程與收集器是併發工作呢?收集器在對象圖上標記顏色,同時用戶線程在修改引用關係(即修改對象圖的結構),這樣可能出現兩種後果。

  • 一種是把原本消亡的對象錯誤標記為存活(即原本應該是白色的對象被誤標為黑色),這不是好事,但其實這種情況是可以容忍的,只不過產生了一點逃過本次收集的浮動垃圾而已,下次收集清理掉就好。
  • 另一種是把原本存活的對象錯誤標記為已消亡(即原本應該是黑色的對象被誤標為白色),這就是非常致命的後果了,程式肯定會因此發生錯誤,下圖演示了這樣的致命錯誤具體是如何產生的。

image-20230222225942722.png

Wilson 於 1994 年在理論上證明瞭,當且僅當以下兩個條件同時滿足時,會產生 “對象消失” 的問題,即原本應該是黑色的對象被誤標為白色:

  • 賦值器插入了一條或多條從黑色對象到白色對象的新引用;
  • 賦值器刪除了全部從灰色對象到該白色對象的直接或間接引用。

因此,我們要解決併發掃描時的對象消失問題,只需破壞這兩個條件的任意一個即可。由此分別產生了兩種解決方案:增量更新(Incremental Update)和原始快照(Snapshot At The Beginning,SATB)。

  • 增量更新要破壞的是第一個條件,當要插入黑色對象指向白色對象的引用關係時,就將這個新插入的引用記錄下來, 等併發掃描結束之後,再將這些記錄過的引用關係中的黑色對象為根,重新掃描一次。這可以簡化理解為,黑色對象一旦新插入了指向白色對象的引用之後,它就變回灰色對象了。
  • 原始快照要破壞的是第二個條件,當要刪除灰色對象指向白色對象的引用關係時,就將這個要刪除的引用記錄下來, 等併發掃描結束之後,再將這些記錄過的引用關係中的灰色對象為根,重新掃描一次。這可以簡化理解為,無論引用關係刪除與否,都會按照剛剛開始掃描那一刻的對象圖快照來進行搜索。

以上無論是對引用關係記錄的插入還是刪除,虛擬機的記錄操作都是通過寫屏障實現的。

在 HotSpot 虛擬機中,增量更新和原始快照這兩種解決方案都有實際應用,譬如,CMS 是基於增量更新來做併發標記的,G1、Shenandoah 則是用原始快照來實現。

參考資料

《深入理解Java虛擬機》第 3 章:垃圾收集器與記憶體分配策略 3.4.6 併發的可達性分析

本文來自博客園,作者:真正的飛魚,轉載請註明原文鏈接:https://www.cnblogs.com/feiyu2/p/17305928.html


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

-Advertisement-
Play Games
更多相關文章
  • 1.struct 簡單介紹 struct 是 Python 的內置模塊, 在使用 socket 通信的時候, 大多數據的傳輸都是以二進位流的形式的存在, 而 struct 模塊就提供了一種機制, 該機制可以將某些特定的結構體類型打包成二進位流的字元串然後再網路傳輸,而接收端也應該可以通過某種機制進行 ...
  • Kafka 環境搭建 kafka 安裝、配置、啟動、測試說明: 1. 安裝:直接官網下載安裝包,解壓到指定位置即可(kafka 依賴的 Zookeeper 在文件中已包含) 下載地址:https://kafka.apache.org/downloads 示例版本:kafka_2.13-2.8.0.t ...
  • SpringCloud OpenFeign-服務調用 1.OpenFeign介紹 https://github.com/spring-cloud/spring-cloud-openfeign OpenFeign是一個聲明式WebService客戶端,使用OpenFeign讓編寫Web Service ...
  • 說明 使用 VLD 記憶體泄漏檢測工具輔助開發時整理的學習筆記。本篇介紹使用 VLD 時的註意事項。同系列文章目錄可見 《記憶體泄漏檢測工具》目錄 1. 官網文檔 可以在 Using-Visual-Leak-Detector 官方文檔里看到如何使用 VLD。 2. 註意事項 以 v2.5.1 版本為例, ...
  • 線程池ThreadPoolExecutor ThreadPoolExecutor 繼承結構 繼承結構如圖所示:ThreadPoolExecutor <- AbstractExecutorService <- ExecutorService <- Executor public class Threa ...
  • Map ​ 哈希表是一種巧妙並且實用的數據結構。它是一個無序的key/value對的集合,其中所有的key 都是不同的,然後通過給定的key可以在常數時間複雜度內檢索、更新或刪除對應的value。 ​ 在Go語言中,一個map就是一個哈希表的引用,map類型可以寫為map[K]V,其中K和V分別 對 ...
  • MongoDB索引優化 作者: 博學谷狂野架構師 GitHub:GitHub地址 (有我精心準備的130本電子書PDF) 只分享乾貨、不吹水,讓我們一起加油!😄 索引簡介 索引通常能夠極大的提高查詢的效率,如果沒有索引,MongoDB在讀取數據時必須掃描集合中的每個文件並選取那些符合查詢條件的記錄 ...
  • 面向對象封裝特點之一就是通過實現好的方法來訪問,限制對數據的不合理訪問,把對象狀態私有化,僅供類的內部進行操作 下方示例,Test方法的number屬性類實例的時候傳遞1,number是一個公開屬性,可以在外部任意修改、訪問,沒有對屬性進行進行約束 class Test: def __init__( ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...