JDK11 | 第六篇 : Epsilon 垃圾收集器

文章首發於公衆號《程序員果果》

地址 : https://mp.weixin.qq.com/s/RhGXJImhp7Xm-wDrpPomkQ

一、簡介

Epsilon(A No-Op Garbage Collector)垃圾回收器控制內存分配,但是不執行任何垃圾回收工作。一旦java的堆被耗盡,jvm就直接關閉。設計的目的是提供一個完全消極的GC實現,分配有限的內存分配,最大限度降低消費內存佔用量和內存吞吐時的延遲時間。一個好的實現是隔離代碼變化,不影響其他GC,最小限度的改變其他的JVM代碼。

二、使用場景

  • Performance testing,什麼都不執行的GC非常適合用於差異性分析。no-op GC可以用於過濾掉GC誘發的新能損耗,比如GC線程的調度,GC屏障的消耗,GC週期的不合適觸發,內存位置變化等。此外有些延遲者不是由於GC引起的,比如scheduling hiccups, compiler transition hiccups,所以去除GC引發的延遲有助於統計這些延遲。
  • Memory pressure testing, 在測試java代碼時,確定分配內存的閾值有助於設置內存壓力常量值。這時no-op就很有用,它可以簡單地接受一個分配的內存分配上限,當內存超限時就失敗。例如:測試需要分配小於1G的內存,就使用-Xmx1g參數來配置no-op GC,然後當內存耗盡的時候就直接crash。
  • VM interface testing, 以VM開發視角,有一個簡單的GC實現,有助於理解VM-GC的最小接口實現。它也用於證明VM-GC接口的健全性。
  • Extremely short lived jobs, 一個短聲明週期的工作可能會依賴快速退出來釋放資源,這個時候接收GC週期來清理heap其實是在浪費時間,因爲heap會在退出時清理。並且GC週期可能會佔用一會時間,因爲它依賴heap上的數據量。
  • Last-drop latency improvements, 對那些極端延遲敏感的應用,開發者十分清楚內存佔用,或者是幾乎沒有垃圾回收的應用,此時耗時較長的GC週期將會是一件壞事。
  • Last-drop throughput improvements, 即便對那些無需內存分配的工作,選擇一個GC意味着選擇了一系列的GC屏障,所有的OpenJDK GC都是分代的,所以他們至少會有一個寫屏障。避免這些屏障可以帶來一點點的吞吐量提升。

三、案例

使用G1垃圾收集器

代碼:

public class TestEpsilon {

    public static void main(String[] args) {
        System.out.println("程序開始");
        boolean flag = true;
        List<Garbage> list = new ArrayList<>();
        long count = 0;
        while (flag) {
            list.add(new Garbage(list.size() + 1));
            if (list.size() == 1000000 && count == 0) {
                list.clear();
                count++;
            }
        }
        System.out.println("程序結束");
    }
}

class Garbage {

    private int number;

    public Garbage(int number) {
        this.number = number;
    }

    /**
     * GC在清除對象時,會調用finalize()方法
     */
    @Override
    public void finalize() {
        System.out.println(this + " : " + number + " is dying");
    }

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }

}

啓動參數:

-Xms100m -Xmx100m

運行程序後,結果如下:

程序開始
...
com.gf.demo8.Garbage@15ddf76b : 305097 is dying
com.gf.demo8.Garbage@35e52705 : 305224 is dying
com.gf.demo8.Garbage@32c14bc1 : 305362 is dying
com.gf.demo8.Garbage@7521660a : 305705 is dying
com.gf.demo8.Garbage@f3da16a : 305948 is dying
com.gf.demo8.Garbage@13fc7287 : 306089 is dying
    at java.base/java.lang.ref.Finalizer.register(Finalizer.java:66)
    at java.base/java.lang.Object.<init>(Object.java:50)
    at com.gf.demo8.Garbage.<init>(TestEpsilon.java:28)
    at com.gf.demo8.TestEpsilon.main(TestEpsilon.java:14)
...

會發現G1一直回收對象,直到內存不夠用。

使用Epsilon垃圾收集器

啓動參數:

UnlockExperimentalVMOptions:解鎖隱藏的虛擬機參數。

-XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -Xms100m -Xmx100m

運行程序後,結果如下:

程序開始
Terminating due to java.lang.OutOfMemoryError: Java heap space

會發現很快就內存溢出了,因爲Epsilon不會去回收對象。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章