天天看點

原來這就是JVM垃圾

原來這就是JVM垃圾

大家都知道,JVM 有垃圾回收的機制,垃圾回收的前提是要知道:什麼是垃圾!然後再是如何識别垃圾!

什麼是垃圾

垃圾,本質上就是沒有引用的對象(們),下面來介紹兩種垃圾

1. 沒有引用指向的對象

下圖是對象間引用的狀态,從正常引用到引用斷開,這個 A 和 C 的引用斷開之後,C 就成了那個垃圾。

​​

原來這就是JVM垃圾

2. 沒有引用指向的一組對象

一個典型的案例如下圖,就是循環引用,這幾個對象看起來都有引用指向,但是其實他們隻是一堆緊緊相擁的垃圾。

原來這就是JVM垃圾

如何識别垃圾

上面介紹了什麼是垃圾,那要如何才能識别出垃圾呢?主要有兩種算法:

  1. 引用計數法
  2. 可達性分析法

1. 引用計數法

算法很簡單,就是在對象頭上加上被引用的次數,對象的被引用的次數為 0 之日,就是其成為垃圾之時!這個算法的優點是垃圾回收及時,隻要對象被引用次數為 0,就可以回收了。

下圖是引用計數的示意圖,對象 A、B、C 都被引用了一次

原來這就是JVM垃圾

如果 A 跟 C 的引用斷開,則 C 的引用次數減一,變為 0,此時 C 就是垃圾

原來這就是JVM垃圾

引用計數法有個緻命的缺點:那就是無法識别出循環引用!

下圖是一個循環引用,明明他們就是一堆垃圾,但是因為被引用次數都不為 0,引用計數法無法識别出他們是垃圾。

原來這就是JVM垃圾

2. 可達性分析法

引用計數法的缺點過于緻命,目前 JVM 采用的是另一種算法來識别垃圾:可達性分析法。

這個算法的基本思路就是:從一系列根對象(​

​GC Roots​

​)開始,根據引用關系向下搜尋,如果某個對象到 ​

​GC Roots​

​ 間沒有任何引用,則證明此對象是不可能再被使用的,也就是垃圾。

其示意圖如下,左邊綠色部分的對象,都可以連向 ​

​GC Roots​

​,是以他們都是存活的對象。而右邊灰色的部分,即使他們是循環引用,他們也跟 ​

​GC Roots​

​ 之間沒有連接配接路徑,是以灰色部分的對象是垃圾。

原來這就是JVM垃圾

那麼,究竟是哪些對象能成為至高無上的 ​

​GC Roots​

​ 呢?以下是主要的 ​

​GC Roots​

​:

  • 虛拟機棧中引用的對象,如各個線程調用的方法堆棧中的參數、局部變量等。
  • 方法區中類的靜态屬性引用的對象,如類的引用類型的靜态變量。
  • 方法區中常量引用的對象,如字元串常量池裡的引用。
  • 本地方法棧中 JNI(Native 方法)引用的對象。
  • 虛拟機内部的引用,如基本資料類型對應的 Class 對象,一些常駐的異常對象(比如 ​

    ​NullPointExcepiton​

    ​、​

    ​OutOfMemoryError​

    ​)等,還有系統類加載器。

優點:解決引用計數器所不能解決的循環引用問題。

缺點:

  1. 耗時:因為需要從 ​

    ​GC Roots​

    ​ 開始逐個檢查引用;
  2. STW:GC 過程中需要保證對象的引用關系不能發生變化,是以 GC 進行時必須停頓所有執行線程(STW:Stop The World)。

總結

第一部分我們介紹了什麼是垃圾:沒有任何引用指向的一個或多個對象。

第二部分介紹了如何識别垃圾,有兩種算法:

  1. 引用計數法:通過給對象添加被引用的次數來識别。優點是回收簡單及時;缺點是無法解決循環引用。
  2. 可達性分析法:從一系列根對象(​

    ​GC Roots​

    ​GC Roots​

    ​ 間沒有任何引用,則此對象就是垃圾。優點是解決了循環引用;缺點是耗時和 STW。

學習使我充實,分享給我快樂!

繼續閱讀