您現在的位置是:首頁 > 棋牌

垃圾回收|Java垃圾回收,這杯咖啡,不僅好喝,而且實用!

  • 由 mySoulCode 發表于 棋牌
  • 2022-12-04
簡介Parallel Old收集器(停止-複製演算法)Parallel Scavenge收集器的老年代版本,並行收集器,吞吐量優先CMS(Concurrent Mark Sweep)收集器(標記-清理演算法)高併發、低停頓,追求最短GC回收停頓

java垃圾回收機制幾種

垃圾回收|Java垃圾回收,這杯咖啡,不僅好喝,而且實用!

Hi! 我是小小,今天是本週的第六篇,本篇將會著重的講解關於Java垃圾回收機制。

垃圾回收的意義

Java語言的顯著特點就是引入了垃圾回收機制,使得C++程式猿最為頭疼的記憶體管理問題就直接解決掉了。這使得Java程式猿編寫程式碼的時候,不需要直接考慮記憶體管理,垃圾回收可以有效的防止記憶體洩露,有效的使用空閒的記憶體。

垃圾回收機制中的演算法

垃圾回收,有以下幾種演算法,這裡對這幾種演算法進行分別的闡述。

引用計數法

演算法分析

引用計數法是垃圾收集中的早期方式,這種方法中,堆中的每個物件例項都會有一個引用計數,當一個物件被建立的時候,這種物件例項會被分配一個變數,該變數計數設定為1,單任何變數被賦值為這個物件引用的時候,計數將會加1,但是超過生命週期的時候,將會減少1,任何計數器為0的時候將會做垃圾回收,當一個例項進行垃圾回收的時候,其引用的任何物件例項引用將會減少1。

優缺點

優點:引用計數器可以很快的執行,但是在程式執行中,對程式需要不被長時間打斷的實時環境比較友好。缺點:無法檢測出迴圈引用,如果父物件有一個對子物件的引用,子物件反過來也會引用父物件,這樣關係永遠不可能為0。

tracing演算法

根搜尋演算法

垃圾回收|Java垃圾回收,這杯咖啡,不僅好喝,而且實用!

根搜尋演算法中,程式吧所有引用關係用一張圖表示,從一個節點GC ROOT開始,尋找對應的引用節點,找到這個節點以後,繼續尋找這個節點的引用節點,當所有的引用節點尋找完畢以後,剩餘的節點被認為是沒有引用的節點。

演算法示意圖

垃圾回收|Java垃圾回收,這杯咖啡,不僅好喝,而且實用!

演算法分析

標記-清除演算法採用從根集合進行掃描,對存活的物件物件標記,標記完畢後,再掃描整個空間中未被標記的物件,進行回收,如上圖所示。標記-清除演算法不需要進行物件的移動,並且僅對不存活的物件進行處理,在存活物件比較多的情況下極為高效,但由於標記-清除演算法直接回收不存活的物件,因此會造成記憶體碎片。

compacting演算法

垃圾回收|Java垃圾回收,這杯咖啡,不僅好喝,而且實用!

標記-整理演算法採用標記-清除演算法一樣的方式進行物件的標記,但在清除時不同,在回收不存活的物件佔用的空間後,會將所有的存活物件往左端空閒空間移動,並更新對應的指標。

copying演算法

垃圾回收|Java垃圾回收,這杯咖啡,不僅好喝,而且實用!

該演算法的提出是為了克服控制代碼的開銷和解決堆碎片的垃圾回收。它開始時把堆分成 一個物件 面和多個空閒面, 程式從物件面為物件分配空間,當物件滿了,基於copying演算法的垃圾 收集就從根集中掃描活動物件,並將每個 活動物件複製到空閒面(使得活動物件所佔的記憶體之間沒有空閒洞),這樣空閒面變成了物件面,原來的物件面變成了空閒面,程式會在新的物件面中分配記憶體。

generation演算法

垃圾回收|Java垃圾回收,這杯咖啡,不僅好喝,而且實用!

分代垃圾回收演算法,分為幾代。

年輕代

所有新生成物件首先會放入年輕代中,年輕代的目標就是儘可能的快速手機哪些生命週期短的物件。

新生代記憶體按照8:1:1的比例分為一個eden區和兩個survivor(survivor0,survivor1)區。一個Eden區,兩個 Survivor區(一般而言)。大部分物件在Eden區中生成。回收時先將eden區存活物件複製到一個survivor0區,然後清空eden區,當這個survivor0區也存放滿了時,則將eden區和survivor0區存活物件複製到另一個survivor1區,然後清空eden和這個survivor0區,此時survivor0區是空的,然後將survivor0區和survivor1區交換,即保持survivor1區為空, 如此往復。

當survivor1區不足以存放 eden和survivor0的存活物件時,就將存活物件直接存放到老年代。若是老年代也滿了就會觸發一次Full GC,也就是新生代、老年代都進行回收

新生代發生的GC也叫做Minor GC,MinorGC發生頻率比較高(不一定等Eden區滿了才觸發)

年老代

1。在年輕代中經歷了N次垃圾回收後仍然存活的物件,就會被放到年老代中。因此,可以認為年老代中存放的都是一些生命週期較長的物件。

2。記憶體比新生代也大很多(大概比例是1:2),當老年代記憶體滿時觸發Major GC即Full GC,Full GC發生頻率比較低,老年代物件存活時間比較長,存活率標記高。

持久代

用於儲存靜態檔案,例如Java類,方法等等。

GC

新生代收集器使用的收集器:Serial、PraNew、Parallel Scavenge

老年代收集器使用的收集器:Serial Old、Parallel Old、CMS

垃圾回收|Java垃圾回收,這杯咖啡,不僅好喝,而且實用!

Serial收集器(複製演算法)

新生代單執行緒收集器,標記和清理都是單執行緒,優點是簡單高效。

Serial Old收集器(標記-整理演算法)

老年代單執行緒收集器,Serial收集器的老年代版本。

ParNew收集器(停止-複製演算法)

新生代收集器,可以認為是Serial收集器的多執行緒版本,在多核CPU環境下有著比Serial更好的表現。

Parallel Scavenge收集器(停止-複製演算法)

並行收集器,追求高吞吐量,高效利用CPU。吞吐量一般為99%, 吞吐量= 使用者執行緒時間/(使用者執行緒時間+GC執行緒時間)。適合後臺應用等對互動相應要求不高的場景。

Parallel Old收集器(停止-複製演算法)

Parallel Scavenge收集器的老年代版本,並行收集器,吞吐量優先

CMS(Concurrent Mark Sweep)收集器(標記-清理演算法)

高併發、低停頓,追求最短GC回收停頓時間,cpu佔用比較高,響應時間快,停頓時間短,多核cpu 追求高響應時間的選擇

GC的執行機制

Scavenge GC

一般情況下,當新物件生成,並且在Eden申請空間失敗時,就會觸發Scavenge GC,對Eden區域進行GC,清除非存活物件,並且把尚且存活的物件移動到Survivor區。然後整理Survivor的兩個區。

Full GC

對整個堆進行整理

Java有了GC同樣會出現記憶體洩露問題

1。靜態集合類像HashMap、Vector等的使用最容易出現記憶體洩露,這些靜態變數的生命週期和應用程式一致,所有的物件Object也不能被釋放,因為他們也將一直被Vector等應用著。2。各種連線,資料庫連線,網路連線,IO連線等沒有顯示呼叫close關閉,不被GC回收導致記憶體洩露。

3。監聽器的使用,在釋放物件的同時沒有相應刪除監聽器的時候也可能導致記憶體洩露。

我是小小,雙魚座的程式猿,我們下期再見~bye

END

Top