Java教程分享:JVM垃圾回收機制之物件回收演算法

千鋒武漢發表於2021-05-06

  前言

  在前面的文章中,介紹了JVM記憶體模型分為:堆區、虛擬機器棧、方法區、本地方法區和程式計數器,其中堆區是JVM中最大的一塊記憶體區域,在Java中的所有物件例項都儲存在此區域,它能被所有執行緒共享。

  在Java中還有一個重要的機制:GC(垃圾收集器),堆是GC管理的主要區域,本文會帶大家瞭解GC機制。

   GC的簡介

  GC(Garbage Collection)垃圾收集機制是Java一個重要特性。不同於C/C++語言需要程式設計師自己管理記憶體的回收,而且這樣做往往容易出錯,導致記憶體洩漏等嚴重問題。

  Java程式設計師不用編寫回收記憶體的程式碼,因為Java有GC機制,它是一個特殊的後臺執行緒,該執行緒對JVM中的記憶體進行標記,並確定哪些需要回收,再透過一定的回收策略自動回收記憶體,它在後臺一直執行,保證JVM不會出現記憶體溢位的問題。

   物件回收的演算法

  那麼GC是如何判斷某個物件的記憶體需要回收呢?GC需要判斷該物件已死,也就是不再被呼叫,如何判斷物件不再被呼叫呢?

  這裡有兩種演算法:

  1、引用計數演算法

  2、可達性分析演算法

  引用計數演算法

  該演算法給每個物件分配一個計數器,當有引用指向這個物件時,計數器加1,當指向該物件的引用失效時,計數器減一。最後如果該物件的計數器為0時,java垃圾回收器會認為該物件是可回收的。

  優點:

  1、實時性高,只要物件計數器為0就進行回收,不用等到記憶體不足的時候。

  2、在垃圾回收過程中,應用無需掛起。

  3、更新物件的計數器時,只是影響到該物件,不會掃描全部物件。

  缺點:

  1、每次引用物件時,都會更新計數器,有時間消耗

  2、不能解決迴圈引用問題

  那什麼是迴圈引用問題呢?我們看下面這段程式碼:

QQ截圖20190426160541

  上面的a、b兩個物件雖然都賦值為null,但是都不能回收,因為存在迴圈引用,它們的計數器不為0.

  可達性分析演算法

  該演算法透過一種被稱作“GC Root”的物件作為起始點,從這些節點開始向下搜尋,搜尋所走過的路徑稱為引用鏈,當一個物件到GC Roots沒有任何引用鏈相連時,則證明此物件時不可用的。

  如下圖:

圖片2

  在Java語言中,可作為GC Roots物件包括下面幾種:

  1)虛擬機器棧中引用的物件

  2)方法區中類靜態屬性引用的物件

  3)方法區常量池中引用的物件

  3)本地方法棧中JNI引用的物件

  再回頭看前面這段程式碼,雖然a和b物件的引用計數都不為0,但是它們作為GC Root物件,最後都賦值為null,導致引用不可達,這樣兩個物件都是可以被回收的。

圖片1

  總結

  本文小千帶我們學習了JVM中的垃圾收集(GC)機制,GC是一個在後臺持續執行的執行緒,幫助我們回收JVM堆中的物件記憶體,保證JVM不會記憶體溢位。

  如何判斷物件記憶體需要回收,有兩個演算法:引用計數演算法和可達性分析演算法。

  引用計數演算法透過判斷物件的引用計數為0,就標記該物件記憶體可以回收,但是不能很好的解決迴圈引用問題;可達性分析演算法透過GC Root向下搜尋,如果引用鏈相連則物件可達,否則標記物件不可達,可以進行回收,這種演算法能很好解決物件迴圈引用問題。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31548651/viewspace-2770942/,如需轉載,請註明出處,否則將追究法律責任。

相關文章