banner
RustyNail

RustyNail

coder. 【blog】https://rustynail.me 【nostr】wss://ts.relays.world/ wss://relays.world/nostr

Java內存區塊內存溢出

想辦法讓 Jvm 的各個分區 OOM

堆內存#

堆內存溢出主要是一直創建物件,但是又不能被 GC 回收(可達性分析,GC Root 和物件之間有可達路徑)就會溢出了。

參數:-Xmx20m -Xms20m -XX:+HeapDumpOnOutOfMemoryError

byte[] a = new byte[21 * 1024 * 1024];

加上HeapDumpOnOutOfMemoryError 可以 dump 出日誌,便於後續分析 OOM 的問題所在

堆疊內存溢出#

虛擬機堆疊裡有個局部變數表,通過不斷創建局部變數,可以讓它爆掉

(這裡沒成功 OOM, 不懂是 Jvm 的原因還是什麼)

參數: -Xss1m -XX:+HeapDumpOnOutOfMemoryError

public void StackOOM() {
        while (true) {
            Thread thread = new Thread(this::job);
            thread.start();
        }
    }

    private void job() {
        while (true) {
        }

    }

方法區溢出#

方法區用於存放類的資訊,所以想要溢出方法區,只要動態地生成大量的類就可以了。比較簡單地生成類的方法是通過使用 Cglib 生成。所以說

有使用 Cglib 的專案是有可能出現方法區溢出異常的,比如 Spring 的 Aop, 如果大量的增強類,會產生很多的類,方法區的大小不夠就會產生異常。

如果使用-XX:PermSize=1M -XX:MaxPermSize=1M, 要確保 jvm 版本低於 8,因為 Java1.8 移除了永久代,類資訊放在了 Meta Space。

控制 Meta space 用 -XX:MetaspaceSize-XX:MaxMetaspaceSize

參數:-XX=10m -XX=10m -Xmx20m -Xms10m

while (true){
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(TestMain.class);
    enhancer.setUseCache(false);
    enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> methodProxy.invokeSuper(o, objects));
    enhancer.create();
}

Exception in thread "main" java.lang.OutOfMemoryError: Metaspace

直接內存溢出#

直接內存溢出通常出現在 Nio 出現的地方,比如 Netty。可以通過 unsafe 方法直接請求系統內存來模擬直接內存溢出。

參數: -XX=10M -XX:+HeapDumpOnOutOfMemoryError

Field field = Unsafe.class.getDeclaredFields()[0];
    field.setAccessible(true);
    Unsafe unsafe = (Unsafe) field.get(null);
    while (true) {
        unsafe.allocateMemory(1 * 1024 * 1024);
}

Exception in thread "main" java.lang.OutOfMemoryError
at sun.misc.Unsafe.allocateMemory(Native Method)

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。