Java 虛擬機枚舉 GC Roots 解析

JVM 堆內存模型鎮樓。html

讀《深刻理解Java 虛擬機》第三章GC算法,關於 GC Roots 枚舉的段落沒說透徹,理解上遇到困惑。所以對這點進行擴展並記錄,發現國內各類博客寫來寫去都是幾乎相同的分析,仍是沒釐清困惑:GC Roots 到底是如何枚舉的,其中用到的 OopMap 是一個什麼樣的數據結構?java

Recap:三大GC算法

一、標記清除算法(Mark-Sweep)算法

二、複製算法(Copying)bash

三、標記整理算法(Mark-Compact)數據結構

三種算法都用到了可達性分析方法來對對象進行標記清除。app

可達性分析方法分三大步驟:

Step One: Enumerations of Roots.ide

找到瓜藤的根。性能

Step Two: Marking all object references starting from the roots.ui

從根節點出發,順藤摸瓜,每次摸到一個瓜,就打上標記--這瓜還沒熟,別摘!google

Step Three: Sweeping all the unmarked objects.

順理成章,那些沒被標記上的瓜天然就是熟了的瓜,通通收走拿去吃掉。

以上過程對應的僞代碼以下:

Void GC() {

    HaltAllProcessing();
    
    ObjectCollection roots = GetRoots();
    for(int i=0; i<roots.Count(); ++i) {
        Mark(roots[i]);
    }
    
    Sweep();
    
}
複製代碼

疑問點:什麼是根節點 GC Roots?

For your application code to reach an object, there should be a root object which is connected to your object as well as capable of accessing from outside the heap. Such root objects that are accessible from outside the Heap are called Garbage Colllection (GC) roots. There are several types of GC roots such as Local variables, Active Java threads, Static variables, JNI References etc. (Just take the ideology here, if you do a quick google search, you may find many conflicting classifications of GC roots)

對於一個 Java 程序而言,對象都位於堆內存塊中,存活的那些對象都被根節點引用着,即根節點 GC Roots 是一些引用類型,天然不在堆裏,那它們位於哪呢?它們能放在哪呢?

答案是放在棧裏,包括:

Local variables 本地變量

Static variables 靜態變量

JNI References JNI引用等

GC Roots are objects that are themselves referenced by the JVM and thus keep every other object from being garbage-collected.

如何快速枚舉 GC Roots?

一、笨方法:遍歷棧裏全部的變量,逐一進行類型判斷,若是是 Reference 類型,則屬於 GC Roots。

二、高效方法:從外部記錄下棧裏那些 Reference 類型變量的類型信息,存成一個映射表 -- 這就是 OopMap 的由來

「在解釋執行時/JIT時,記錄下棧上某個數據對應的數據類型,好比地址1上的」12344「值是一個堆上地址引用,數據類型爲com.aaaa.aaa.AAA)

如今三種主流的高性能JVM實現,HotSpot、JRockit和J9都是這樣作的。其中,HotSpot把這樣的數據結構叫作 OopMap,JRockit裏叫作livemap,J9裏叫作GC map。」

GC 時,直接根據這個 OopMap 就能夠快速實現根節點枚舉了。

參考連接:

Understanding Java Garbage Collection

JVM中的OopMap

相關文章
相關標籤/搜索