GC與記憶體分配策略

来源:https://www.cnblogs.com/HuiH/archive/2019/12/05/11986215.html
-Advertisement-
Play Games

一、GC 第一步:判斷對象是否已死?有兩種方法:第一種是引用計數法,即給對象添加一個引用計數器,當被引用時,計數器就+1;當引用失效時,就-1;當計數器為0時,代表對象沒有被引用。但是計數器的缺點就是:對象之間相互引用時導致計數器不為零,無法被回收。第二種方法是可達性分析法,即通過定義一系列的GC ...


一、GC

  第一步:判斷對象是否已死?有兩種方法:第一種是引用計數法,即給對象添加一個引用計數器,當被引用時,計數器就+1;當引用失效時,就-1;當計數器為0時,代表對象沒有被引用。但是計數器的缺點就是:對象之間相互引用時導致計數器不為零,無法被回收。第二種方法是可達性分析法,即通過定義一系列的GC Roots對象作為起始點,從這些起點向下搜索,當一個對象到GC Roots沒有任何引用鏈時,則此對象是不可用的。

    可以作為GC Roots的對象包括:虛擬機棧中引用的對象、方法去種類靜態屬性或常量引用的對象,本地方法棧中native方法引用的對象。

    這裡再說明一下引用!!!

    引用分為:強引用:把一個對象賦給一個引用變數,這個引用變數就是強引用。(強引用的對象不會被回收)

         軟引用:用來描述一些還有用但非必需的對象。(在系統將要發生溢出異常之前,將這些對象列入回收範圍進行二次回收,如果回收之後還沒有足夠記憶體,才會拋出異常。利用SoftReference類實現軟引用

         弱引用:用來描述非必需的對象,它的強度較軟引用弱。(當發生GC時,無論當前記憶體是否足夠,都會回收被弱引用關聯的對象。利用WeakReference類來實現弱引用

         虛引用:主要作用是跟蹤對象被垃圾回收的狀態,是最弱的引用關係。(PhantomReference類來實現虛引用)

  一個對象的死亡,至少要經歷兩次標記的過程:如果對象在進行可達性分析後發現沒有與GC Roots相連的引用鏈,那它將會被第一次標記並且進行一次篩選,篩選的條件是此對象是否有必要執行finalize()方法。如果對象沒有覆蓋finalize()方法或者finalize方法已經被虛擬機調用過,則沒有必要執行。如果這個對象被判定為有必要執行finalize方法,那麼這個對象將會放置在一個叫做F-Queue的隊列中,併在稍後由虛擬機自動建立一個低優先順序的Finalizer線程去執行它。

  finalize方法是對象逃脫死亡命運的最後一次機會,稍後GC將對F-Queue中的對象進行第二次標記,如果對象重新與引用鏈的任何一個對象建立關聯,那在第二次標記時會將它移除“即將回收”的集合;如果對象沒有逃脫,那麼它就真的被回收了。

  回收方法區:永久帶的垃圾收集主要回收廢棄常量和無用的類。判斷一個類是不是“無用的類”條件:該類所有的實例都已經被回收;載入該類的ClassLoader已經被回收;該類對應的java.lang.Class對象沒有在任何地方被引用,無法通過反射訪問該類方法。

  第二步:垃圾收集演算法

    第一種是標記-清除演算法(mark-sweep),演算法分為標記和清除兩部分:首先標記出所有要回收的對象,標記完成後統一回收所有被標記的對象。缺點:一個是標記和清除兩個過程效率不高,另一個是標記和清除之後產生大量不連續的空間碎片,導致以後分配較大對象時找不到足夠的記憶體而提前觸發GC。

    第二種是複製演算法(copying),它是將可用記憶體按容量劃分為大小相等的兩塊,每次只使用其中一塊。當這一塊記憶體用完後,就將還存活的對象複製到另一塊上面,然後再把已使用過的記憶體一次清理掉。優點:解決了記憶體碎片化,實現簡單,運行高效;缺點:將記憶體縮小為原來的一半,這樣代價較大。

    第三種是標記-整理演算法(mark-compact),分為標記和整理兩部分,首先標記出所有要回收的對象,將所有存活的對象都向一端移動,然後直接清理掉端邊以外的記憶體。

    第四種是分代收集演算法,就是根據對象存貨周期的不同將記憶體劃分為新生代和老年代,然後根據每個年代特性採用合適的演算法。在新生代中每次都有大量對象死去,只有少量存活,那麼就採用複製演算法;而老年代對象存活率高沒有額外空間對它進行擔保,就必須使用標記-清除或標記-整理演算法來回收。

  第三步:垃圾收集器

    Serial收集器,是單線程收集器,它進行GC時必須暫停其他所有的工作線程,直到它收集結束,這項工作實際是虛擬機在後臺自動發起和自動完成的。

    ParNew收集器,就是Serial收集器的多線程版本,除了使用多線程進行垃圾收集之外,其餘行為與Serial收集器一樣。

    Parallel Scavenge收集器,是使用複製演算法的新生代收集器,又是並行的多線程收集器。它的目的是達到一個可控制的吞吐量,高效率地利用CPU時間, PS收集器提供了控制最大垃圾收集停頓時間的 -XX:MaxGCPauseMillis參數和直接設置吞吐量大小的 -XX:GCTimeRatio參數用於精確控制吞吐量。(PS收集器還有一個參數-XX:+UseAdaptiveSizePolicy,這是一個開關參數,這個開關打開後,就不用手工指定新生代的大小、Eden和Survivor區的比例、晉升老年代對象的大小等細節參數,虛擬機會根據當前系統的運行情況收集性能監控信息動態調整這些參數,這種調節方式稱為GC自適應的調節機制)。

    Serial Old收集器,是單線程收集器,使用標記-整理演算法,是Serial收集器的老年代版本,是給Client模式下的虛擬機使用。

    Paralled Old收集器,是Parallel Scavenge收集器的老年代版本,使用多線程和標記-整理演算法。

    CMS收集器,是一種以獲取最短回收停頓時間為目標的收集器,使用多線程和標記-清楚演算法。

      運作過程分為:初始標記(僅僅只是標記一下GC Roots能直接關聯到的對象)

             併發標記(進行GC Roots Tracing 的過程)

             重新標記(為了修正併發標記期間因用戶程式繼續運作而導致標記產生變動的那一部分標記記錄)

             併發清除(清除GC Roots不可達的對象,不需要暫停工作線程)。

      優點:併發收集、低停頓;

      缺點:CMS收集器對CPU資源非常敏感、CMS收集器無法處理浮動垃圾、基於標記-清除演算法會產生大量的空間碎片。

    G1收集器,是一款面向服務端的垃圾收集器,G1具備並行與併發、分代收集、空間整合(基於標記-整理和複製演算法實現,不會產生空間碎片)、可預測停頓的特點;G1收集器中它將Java堆劃分為多個大小相等的獨立區域,獨立使用和回收,這樣可以控制一次回收多個區域,減少一次GC所產生的停頓(區域劃分機制)。G1之所以能建立可預測的停頓模型,是因為G1跟蹤各個區域裡面的垃圾堆積的價值大小,在後臺維護一個優先列表,每次根據允許的收集時間,優先回收價值最大的區域(優先區域回收機制)。為了避免全堆掃描,G1使用Remembered Set來管理相關的對象引用信息。當進行記憶體回收時,在GC根節點的枚舉範圍中加入Remembered Set即可保證不對全堆掃描也不會有遺漏。

      運作過程分為:初始標記(僅僅只是標記一下GC Roots能直接關聯的對象,並修改TAMS的值,讓下一階段用戶程式併發運行時,能在正確可用的region中創建對象,此階段需要停頓線程,但時間很短)

             併發標記(從GC Root開始對堆中的對象進行可達性分析,找出存活的對象,耗時長,但可與用戶線程併發執行)

             最終標記(為了修正併發標記期間因用戶程式繼續運行而導致標記產生變動的那一部分標記記錄並把Remembered Set Logs的數據合併到Remembered Set 中,此階段需要停頓線程,但可併發執行)

             篩選回收(首先根據各個region的回收價值和成本進行排序,根據用戶所期望的GC停頓時間來制定回收計劃)

    並行(Parallel):指多條垃圾收集線程並行工作,但此時用戶線程仍然處於等待狀態。

    併發(Concurrent):指用戶線程與垃圾收集線程同時執行。

二、記憶體分配與回收策略

  大多數情況下,對象分配在新生代的Eden區上,分配規則是不固定的,取決於當前使用的垃圾收集器以及虛擬機中與記憶體相關的參數設置。

  新生代:用來存放新產生的對象,占用1/3空間;新生代分為一個Eden區和兩個Survivor區(FromSurvivor和ToSurvivor);當Eden區沒有足夠空間進行分配時,虛擬機將會進行一次Minor GC。進行一次Minor GC後的對象進入FromSurvivor區,當From和Eden區沒有可用空間時,會進行第二次Minor GC,將存活的對象移到ToSurvivor區。

  大對象(需要大量連續記憶體空間的對象)直接進入老年代;虛擬機提供了一個-XX:PretenureSizeThreshold參數,令大於這個設置值的對象直接在老年代分配,這樣做避免了在Eden區及兩個Survivor區之間發生大量的記憶體複製。長期存活的對象將進入老年代,如果對象在Eden區出生並且經過第一次Minor GC後仍然存活,將被移動到Survivor區,並且對象年齡設為1。對象在Survivor區中每經過一次Minor GC,年齡就+1,當它的年齡增加到一定程度時(預設為15),就將會被晉升到老年代中。對象晉升老年代的年齡閾值,可以通過參數-XX:MaxTenuringThreshold設置。

  動態對象年齡判定:如果在Survivor區中相同年齡的所有對象大小總和大於Survivor區的一半,年齡大於或等於該年齡的對象可以直接進入老年代。

  空間分配擔保:當出現大量對象在Minor GC後仍然存活就需要老年代進行分配擔保,把Survivor區無法容納的對象直接進入老年代中。前提是老年代本身有容納這些對象的剩餘空間。

  在發生Minor GC之前,虛擬機會先檢查老年代最大可用的連續空間是否大於新生代所有對象總大小或者歷次晉升到老年代對象的平均大小,如果大於就進行MinorGC,否則將進行FullGC。


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

-Advertisement-
Play Games
更多相關文章
  • 原鏈接:https://zhuanlan.zhihu.com/p/73001806 在使用PC時與PC交互的主要途徑是看屏幕顯示、聽聲音,點擊滑鼠和敲鍵盤等等。在自動化辦公的趨勢下,繁瑣的工作可以讓程式自動完成。比如自動化測試、自動下單交易等。很多軟體除了可以GUI方式操作外還可以用CLI介面操作, ...
  • IO概述 當我們在生活中把電腦上的數據拷貝到U盤或者硬碟上時,就是進行數據傳輸,按照數據的流動方向,我們分為輸入(input)和輸出(output),即就是所謂IO流 Java中I/O操作主要是指使用 java.io 包下的內容,進行輸入、輸出操作。輸入也叫做讀取數據,輸出也叫做作寫出數據 IO的分 ...
  • ——日拱一卒,不期而至! 你好,我是彤哥,本篇是netty系列的第七篇。 簡介 上一章我們一起學習了Java NIO的核心組件Buffer,它通常跟Channel一起使用,但是它們在網路IO中又該如何使用呢,今天我們將一起學習另一個NIO核心組件—— Selector ,沒有它可以說就乾不起來網路I ...
  • 在控制面板的程式與功能里啟用和關閉windows功能打開,適用於linux的windows子系統 在微軟商店裡搜索ubuntu,直接點擊安裝就可以了 安裝完成後的windows與linux的磁碟映射見下圖 配置開發環境,下載和安裝vscode,打開後直接讓安裝一個擴展可以連接子系統的目錄 windo ...
  • Java編程思想總結(一)對象導論 1.1 抽象過程 萬物皆對象。 程式是對象的集合(即:類),他們通過發送消息(調用方法)來告知彼此要做的。 每個對象都有自己的由其他對象所構成的存儲(引用其他對象或基本類型,即組合)。 每個對象都擁有其類型。每個類最重要的區別於其他類的特征就是“可以發送什麼樣的消 ...
  • 一、基礎 ArrayList不是線程安全的,多線程建議使用Vector或者CopyOnWriteArrayList; 底層實現是Object數組。預設容量DEFAULT_CAPACITY為10,最大數組大小MAX_ARRAY_SIZE為Integer.MAX_VALUE-8; 實現了RandomAc ...
  • 在posix標準推出後,socket在各大主流OS平臺上都得到了很好的支持。而Golang是自帶runtime的跨平臺編程語言,Go中提供給開發者的socket API是建立在操作系統原生socket介面之上的。但golang 中的socket介面在行為特點與操作系統原生介面有一些不同。本文將對結合 ...
  • Problem Description 輸入N個整數順序建立一個單鏈表,將該單鏈表拆分成兩個子鏈表,第一個子鏈表存放了所有的偶數,第二個子鏈表存放了所有的奇數。兩個子鏈表中數據的相對次序與原鏈表一致。 Input 第一行輸入整數N;;第二行依次輸入N個整數。 Output 第一行分別輸出偶數鏈表與奇 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...