目錄
收集演算法
物件標記過程
垃圾收集器
首頁 Java java教程 Java GC的那些事(2)

Java GC的那些事(2)

Feb 22, 2017 am 10:09 AM

收集演算法

垃圾收集演算法主要有:標記-清除、複製和標記-整理。

1、標記-清除演算法

處理回收的物件進行標記。

演算法缺點:效率問題,標記和清除過程效率都很低;空間問題,收集之後會產生大量的記憶體碎片,不利於大物件的分配。

2、複製演算法

複製演算法將可用記憶體分割成大小相等的兩塊A和B,每次只使用其中一塊,當A的記憶體用完了,就把存活的對象複製到B,並清空A的內存,不僅提高了標記的效率,因為只需要標記存活的對象,同時也避免了內存碎片的問題,代價是可用內存縮小為原來的一半。

3、標記-整理演算法

在老年代中,物件存活率較高,複製演算法的效率很低。在標記-整理演算法中,標記出所有存活的對象,並移動到一端,然後直接清理邊界以外的記憶體。

物件標記過程

在可達性分析過程中,為了準確找出與GC Roots相關聯的對象,必須要求整個執行引擎看起來像是被凍結在某個時間點上,即暫停所有運行中的線程,不可以出現物件的引用關係還在不斷變化的情況。

如何快速列舉GC Roots?

GC Roots主要在全域性的引用(常數或類別靜態屬性)與執行上下文(本地變數表中的引用)中,許多應用僅僅方法區就上百兆,如果進行遍歷查找,效率會非常低。

在HotSpot中,使用一組稱為OopMap的資料結構進行實作。類別載入完成時,HotSpot把物件內什麼偏移量上是什麼類型的資料計算出來儲存到OopMap中,透過JIT編譯出來的本機程式碼,也會記錄下棧和暫存器中哪些位置是引用。 GC發生時,透過掃描OopMap的資料就可以快速標識存活的物件。

如何安全的GC?

執行緒運行時,只有在到達安全點(Safe Point)才能停頓下來進行GC。

基於OopMap資料結構,HotSpot可以快速完成GC Roots的遍歷,不過HotSpot並不會為每個指令都產生對應的OopMap,只會在Safe Point處記錄這些資訊。

所以Safe Point的選擇很重要,如果太少可能導致GC等待的時間太長,如果太頻繁可能導致運行時的效能問題。大部分指令的執行時間都非常短暫,通常會選擇一些執行時間較長的指令作為Safe Point,如方法呼叫、循環跳躍和異常跳躍等。

關於Safe Point更多的信息,可以看看這篇文章JVM的Stop The World,安全點,黑暗的地底世界

發生GC時,如何讓所有線程跑到最近的Safe Point再暫停?

當發生GC時,不直接對執行緒進行中斷操作,而是簡單的設定一個中斷標誌,每個執行緒運行到Safe Point的時候,主動去輪詢這個中斷標誌,如果中斷標誌為真,則將自己進行中斷掛起。

這裡忽略了一個問題,當發生GC時,運行中的線程可以跑到Safe Point後進行掛起,而那些處於Sleep或Blocked狀態的線程在此時無法響應JVM的中斷請求,無法到Safe Point處進行掛起,針對這種情況,可以使用安全區域(Safe Region)進行解決。

Safe Region是指在一段程式碼片段中,物件的引用關係不會發生變化,在這個區域中的任何位置開始GC都是安全的。

1、當執行緒運行到Safe Region的程式碼時,首先標識已經進入了Safe Region,如果這段時間內發生GC,JVM會忽略標識為Safe Region狀態的執行緒;

2、當執行緒即將離開Safe Region時,會檢查JVM是否已經完成GC,如果完成了,則繼續運行,否則執行緒必須等待直到收到可以安全離開Safe Region的訊號為止;

垃圾收集器

Java虛擬機器規格並沒有規定垃圾收集器應該如何實現,使用者可以根據系統特點對各個區域所使用的收集器進行組合使用。

Java GC的那些事(2)

上圖展示了7種不同分代的收集器,如果兩兩之間存在連線,表示可以組合使用。

1、Serial收集器(序列GC)

Serial 是採用單一執行緒並基於複製演算法工作在新生代的收集器,進行垃圾收集時,必須暫停其他所有的工作線程。對於單CPU環境來說,Serial由於沒有執行緒互動的開銷,可以很有效率的進行垃圾收集動作,是Client模式下新生代預設的收集器。

2、ParNew收集器(並行GC)

ParNew其實是serial的多執行緒版本,除了使用多個執行緒進行垃圾收集之外,其餘行為與Serial一樣。

3、Parallel Scavenge收集器(並行回收GC)

Parallel Scavenge是一個採用多執行緒基於複製演算法並工作在新生代的收集器,其關注點在於達到一個可控​​的吞吐量,經常被稱為「吞吐量優先」的收集器。

吞吐量= 使用者程式碼運行時間/(使用者程式碼運行時間+ 垃圾收集時間)

#Parallel Scavenge提供了兩個參數用於精確控制吞吐量:

1、-XX:MaxGCPauseMillis 設定垃圾收集的最大停頓時間

2、-XX:GCTimeRatio 設定吞吐量大小

4、Serial Old收集器(序列GC)

Serial Old 是一個採用單執行緒基於標記-整理演算法並工作在老年代的收集器,是Client模式下老年代預設的收集器。

5、Parallel Old收集器(平行GC)

Parallel Old是一個採用多執行緒基於標記-整理演算法並工作在老年代的收集器。在註重吞吐量以及CPU資源敏感的場合,可以優先考慮Parallel Scavenge和Parallel Old的收集器組合。

6、CMS收集器(並發GC)

CMS(Concurrent Mark Sweep)是一種以獲取最短回收停頓時間為目標的收集器,工作在老年代,基於「標記-清除」演算法實現,整個過程分為以下4步:

1、初始標記:這個過程只​​是標記以下GC Roots能夠直接關聯的對象,但仍然會Stop The World;

2、並發標記:進行GC Roots Tracing的過程,可以和使用者執行緒一起工作。

3、重新標記:用於修正並發標記期間由於使用者程式繼續運行而導致標記產生變動的那部分記錄,這個過程會暫停所有執行緒,但其停頓時間遠比並發標記的時間短;

4、並發清理:可以和使用者執行緒一起工作。

CMS收集器的缺點:

1、對CPU資源比較敏感,在並發階段,雖然不會導致用戶執行緒停頓,但會佔用一部分執行緒資源,降低系統的總吞吐量。

2、無法處理浮動垃圾,在並發清理階段,用戶執行緒的運作依然會產生新的垃圾對象,這部分垃圾只能在下次GC時收集。

3、CMS是基於標記-清除演算法實現的,意味著收集結束後會造成大量的記憶體碎片,可能導致出現老年代剩餘空間很大,卻無法找到足夠大的連續空間分配當前對象,不得不提前觸發一次Full GC。

JDK1.5實作中,當老年代空間使用率達到68%時,就會觸發CMS收集器,如果應用中老年代增長不是太快,可以透過-XX:CMSInitiatingOccupancyFraction參數提高觸發百分比,從而降低記憶體回收次數提高系統效能。

JDK1.6實作中,觸發CMS收集器的閾值已經提升到92%,如果CMS運行期間預留的記憶體無法滿足用戶執行緒需要,會出現一次」Concurrent Mode Failure」失敗,這是虛擬機會啟動Serial Old收集器對老年代進行垃圾收集,當然,這樣應用的停頓時間就更長了,所以這個閾值也不能設置的太高,如果導致了”Concurrent Mode Failure”失敗,反而會降低性能,至於如何設定這個閾值,還得長時間的對老年代空間的使用情況進行監控。

7、G1收集器

G1(Garbage First)是JDK1.7提供的一個工作在新生代和老年代的收集器,基於“標記-整理」演算法實現,在收集結束後可以避免記憶體碎片問題。

G1優點:

1、並行與並發:充分利用多CPU來縮短Stop The World的停頓時間;

2、分代收集:不需要其他收集配合就可以管理整個Java堆,採用不同的方式處理新建的物件、已經存活一段時間和經歷過多次GC的物件來獲取更好的收集效果;

#3.空間整合:與CMS的”標記-清除”演算法不同,G1在運行期間不會產生內存空間碎片,有利於應用的長時間運行,且分配大對象時,不會導致由於無法申請到足夠大的連續記憶體而提前觸發一次Full GC;

4、停頓預測:G1中可以建立可預測的停頓時間模型,能讓使用者明確指定在M毫秒的時間片段內,消耗在垃圾收集上的時間不得超過N毫秒。

使用G1收集器時,Java堆的記憶體佈局與其他收集器有很大區別,整個Java堆會被劃分為多個大小相等的獨立區域Region,新生代和老年代不再是物理隔離了,都是一部分Region(不需要連續)的集合。 G1會追蹤各個Region的垃圾收集情況(回收空間大小和回收消耗的時間),維護一個優先列表,根據允許的收集時間,優先回收價值最大的Region,避免在整個Java堆上進行全區域的垃圾回收,確保了G1收集器可以在有限的時間內盡可能收集更多的垃圾。

不過問題來了:使用G1收集器,一個物件分配在某個Region中,可以和Java堆上任意的物件有引用關係,那麼如何判定物件是否存活,是否需要掃描整個Java堆?其實這個問題在之前收集器中也存在,如果回收新生代的物件時,不得不同時掃描老年代的話,會大大降低Minor GC的效率。

針對這種情況,虛擬機器提供了一個解決方案:G1收集器中Region之間的物件參考關係和其他收集器中新生代與老年代之間的物件參考關係被保存在Remenbered Set資料結構中,用來避免全堆掃描。 G1中每個Region都有一個對應的Remenbered Set,當虛擬機器發現程式對Reference類型的資料進行寫入操作時,會產生一個Write Barrier暫時中斷寫入操作,檢查Reference所引用的物件是否處於相同的Region中,如果不是,則透過CardTable把相關參考資訊記錄到被引用物件所屬Region的Remenbered Set中。

Java GC 的那些事(1)

Java GC的那些事(2)

以上就是Java GC的那些事(2) 的內容,更相關內容請關注PHP中文網(www.php.cn)!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

Java Spring 面試題 Java Spring 面試題 Aug 30, 2024 pm 04:29 PM

在本文中,我們保留了最常被問到的 Java Spring 面試問題及其詳細答案。這樣你就可以順利通過面試。

突破或從Java 8流返回? 突破或從Java 8流返回? Feb 07, 2025 pm 12:09 PM

Java 8引入了Stream API,提供了一種強大且表達力豐富的處理數據集合的方式。然而,使用Stream時,一個常見問題是:如何從forEach操作中中斷或返回? 傳統循環允許提前中斷或返回,但Stream的forEach方法並不直接支持這種方式。本文將解釋原因,並探討在Stream處理系統中實現提前終止的替代方法。 延伸閱讀: Java Stream API改進 理解Stream forEach forEach方法是一個終端操作,它對Stream中的每個元素執行一個操作。它的設計意圖是處

PHP:網絡開發的關鍵語言 PHP:網絡開發的關鍵語言 Apr 13, 2025 am 12:08 AM

PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7

PHP與Python:了解差異 PHP與Python:了解差異 Apr 11, 2025 am 12:15 AM

PHP和Python各有優勢,選擇應基於項目需求。 1.PHP適合web開發,語法簡單,執行效率高。 2.Python適用於數據科學和機器學習,語法簡潔,庫豐富。

Java程序查找膠囊的體積 Java程序查找膠囊的體積 Feb 07, 2025 am 11:37 AM

膠囊是一種三維幾何圖形,由一個圓柱體和兩端各一個半球體組成。膠囊的體積可以通過將圓柱體的體積和兩端半球體的體積相加來計算。本教程將討論如何使用不同的方法在Java中計算給定膠囊的體積。 膠囊體積公式 膠囊體積的公式如下: 膠囊體積 = 圓柱體體積 兩個半球體體積 其中, r: 半球體的半徑。 h: 圓柱體的高度(不包括半球體)。 例子 1 輸入 半徑 = 5 單位 高度 = 10 單位 輸出 體積 = 1570.8 立方單位 解釋 使用公式計算體積: 體積 = π × r2 × h (4

PHP與Python:核心功能 PHP與Python:核心功能 Apr 13, 2025 am 12:16 AM

PHP和Python各有優勢,適合不同場景。 1.PHP適用於web開發,提供內置web服務器和豐富函數庫。 2.Python適合數據科學和機器學習,語法簡潔且有強大標準庫。選擇時應根據項目需求決定。

PHP與其他語言:比較 PHP與其他語言:比較 Apr 13, 2025 am 12:19 AM

PHP適合web開發,特別是在快速開發和處理動態內容方面表現出色,但不擅長數據科學和企業級應用。與Python相比,PHP在web開發中更具優勢,但在數據科學領域不如Python;與Java相比,PHP在企業級應用中表現較差,但在web開發中更靈活;與JavaScript相比,PHP在後端開發中更簡潔,但在前端開發中不如JavaScript。

創造未來:零基礎的 Java 編程 創造未來:零基礎的 Java 編程 Oct 13, 2024 pm 01:32 PM

Java是熱門程式語言,適合初學者和經驗豐富的開發者學習。本教學從基礎概念出發,逐步深入解說進階主題。安裝Java開發工具包後,可透過建立簡單的「Hello,World!」程式來實踐程式設計。理解程式碼後,使用命令提示字元編譯並執行程序,控制台上將輸出「Hello,World!」。學習Java開啟了程式設計之旅,隨著掌握程度加深,可創建更複雜的應用程式。

See all articles