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
  • .Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 實測可以完整運行在 win7sp1/win10/win11. 如果用其他工具打包,還可以運行在mac/linux下, 傳送門BlazorHybrid 發佈為無依賴包方式 安裝 WebView2Runtime 1.57 M ...
  • 目錄前言PostgreSql安裝測試額外Nuget安裝Person.cs模擬運行Navicate連postgresql解決方案Garnet為什麼要選擇Garnet而不是RedisRedis不再開源Windows版的Redis是由微軟維護的Windows Redis版本老舊,後續可能不再更新Garne ...
  • C#TMS系統代碼-聯表報表學習 領導被裁了之後很快就有人上任了,幾乎是無縫銜接,很難讓我不想到這早就決定好了。我的職責沒有任何變化。感受下來這個系統封裝程度很高,我只要會調用方法就行。這個系統交付之後不會有太多問題,更多應該是做小需求,有大的開發任務應該也是第二期的事,嗯?怎麼感覺我變成運維了?而 ...
  • 我在隨筆《EAV模型(實體-屬性-值)的設計和低代碼的處理方案(1)》中介紹了一些基本的EAV模型設計知識和基於Winform場景下低代碼(或者說無代碼)的一些實現思路,在本篇隨筆中,我們來分析一下這種針對通用業務,且只需定義就能構建業務模塊存儲和界面的解決方案,其中的數據查詢處理的操作。 ...
  • 對某個遠程伺服器啟用和設置NTP服務(Windows系統) 打開註冊表 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpServer 將 Enabled 的值設置為 1,這將啟用NTP伺服器功 ...
  • title: Django信號與擴展:深入理解與實踐 date: 2024/5/15 22:40:52 updated: 2024/5/15 22:40:52 categories: 後端開發 tags: Django 信號 松耦合 觀察者 擴展 安全 性能 第一部分:Django信號基礎 Djan ...
  • 使用xadmin2遇到的問題&解決 環境配置: 使用的模塊版本: 關聯的包 Django 3.2.15 mysqlclient 2.2.4 xadmin 2.0.1 django-crispy-forms >= 1.6.0 django-import-export >= 0.5.1 django-r ...
  • 今天我打算整點兒不一樣的內容,通過之前學習的TransformerMap和LazyMap鏈,想搞點不一樣的,所以我關註了另外一條鏈DefaultedMap鏈,主要調用鏈為: 調用鏈詳細描述: ObjectInputStream.readObject() DefaultedMap.readObject ...
  • 後端應用級開發者該如何擁抱 AI GC?就是在這樣的一個大的浪潮下,我們的傳統的應用級開發者。我們該如何選擇職業或者是如何去快速轉型,跟上這樣的一個行業的一個浪潮? 0 AI金字塔模型 越往上它的整個難度就是職業機會也好,或者說是整個的這個運作也好,它的難度會越大,然後越往下機會就會越多,所以這是一 ...
  • @Autowired是Spring框架提供的註解,@Resource是Java EE 5規範提供的註解。 @Autowired預設按照類型自動裝配,而@Resource預設按照名稱自動裝配。 @Autowired支持@Qualifier註解來指定裝配哪一個具有相同類型的bean,而@Resourc... ...