Stories

Detail Return Return

面試被問:OOM類型有哪些?怎麼答?

大家好,我是小富~

面試官:OOM類型有哪些?

你:就是老年代放不下了嘛!

面試官:等消息吧!

OOM(Out Of Memory) 錯誤有多種類型,每種類型對應不同的內存區域或觸發場景。以下是常見的 OOM 類型及其產生原因:


1. java.lang.OutOfMemoryError: Java heap space

  • 觸發原因:堆內存(存放對象實例)不足,無法分配新對象。
  • 典型場景

    • 內存泄漏:對象被無意長期引用(如靜態集合、未關閉的資源),無法被 GC 回收。
    • 堆大小不足:JVM 堆參數(-Xmx)設置過小,或程序需要處理的數據量超出預期。
    • 大對象分配:一次性申請超大對象(如大數組)。

示例

// 不斷向集合中添加對象導致堆溢出
List<Object> list = new ArrayList<>();
while (true) {
    list.add(new Object());
}

解決方案

  • 檢查內存泄漏(使用 jmap + MAT 分析堆轉儲)。
  • 調整堆大小(-Xmx-Xms)。
  • 優化代碼邏輯,減少對象生命週期。

2. java.lang.OutOfMemoryError: Metaspace(Java 8+)或 PermGen space(Java 7-)

  • 觸發原因:元空間(Metaspace)或永久代(PermGen)內存不足,用於存儲類元數據、方法信息等。
  • 典型場景

    • 動態生成大量類(如使用 CGLib、反射、動態代理)。
    • 類加載器未正確釋放(如頻繁部署的 Web 應用導致舊類未卸載)。

示例

// 使用 CGLib 動態生成大量代理類
Enhancer enhancer = new Enhancer();
while (true) {
    enhancer.setSuperclass(OOM.class);
    enhancer.setCallback((MethodInterceptor) (obj, method, args, proxy) -> proxy.invokeSuper(obj, args)));
    enhancer.create();
}

解決方案

  • 調整元空間大小(-XX:MaxMetaspaceSize)。
  • 檢查類加載器泄漏或動態類生成邏輯。

3. java.lang.OutOfMemoryError: Direct buffer memory

  • 觸發原因:直接內存(Direct Memory,通過 ByteBuffer.allocateDirect() 分配)耗盡。
  • 典型場景

    • 頻繁申請直接內存但未及時釋放(需依賴 System.gc()Cleaner 機制)。
    • JVM 直接內存參數(-XX:MaxDirectMemorySize)設置過小。

示例

// 不斷申請直接內存
List<ByteBuffer> buffers = new ArrayList<>();
while (true) {
    buffers.add(ByteBuffer.allocateDirect(1024 * 1024)); // 1MB
}

解決方案

  • 檢查直接內存使用代碼,確保及時釋放。
  • 調整 -XX:MaxDirectMemorySize

4. java.lang.OutOfMemoryError: Unable to create new native thread

  • 觸發原因:操作系統限制線程數量,無法創建新線程。
  • 典型場景

    • 線程數超過系統限制(如 Linux 的 ulimit -u)。
    • 每個線程的棧內存(-Xss)設置過大,導致總內存佔用超出。

示例

// 無限創建線程
while (true) {
    new Thread(() -> {
        try { Thread.sleep(1000000); } catch (InterruptedException e) {}
    }).start();
}

解決方案

  • 減少線程數(使用線程池)。
  • 調整 -Xss 減小線程棧大小。
  • 修改系統線程數限制。

5. java.lang.OutOfMemoryError: Requested array size exceeds VM limit

  • 觸發原因:嘗試分配超過 JVM 限制的數組(通常接近 Integer.MAX_VALUE)。
  • 典型場景:錯誤計算數組長度,如 new int[Integer.MAX_VALUE]

解決方案

  • 檢查數組長度計算邏輯,使用合理的數據結構。

6. java.lang.OutOfMemoryError: GC Overhead limit exceeded

  • 觸發原因:GC 頻繁執行但回收效率極低(如 98% 時間用於 GC,僅回收 2% 內存)。
  • 典型場景:堆內存幾乎被佔滿,且存在大量無法回收的對象(內存泄漏)。

解決方案

  • 檢查內存泄漏或優化 GC 策略(如調整堆大小、更換垃圾回收器)。

7. java.lang.OutOfMemoryError: CodeCache(JIT 編譯代碼緩存溢出)

  • 觸發原因:JIT 編譯器生成的本地代碼佔滿代碼緩存區。
  • 典型場景:高頻動態編譯大量方法(如複雜的熱點代碼)。

解決方案

  • 調整代碼緩存大小(-XX:ReservedCodeCacheSize)。
  • 關閉分層編譯(-XX:-TieredCompilation)。

總結

OOM 的根本原因是 JVM 內存區域不足資源耗盡,需結合錯誤類型分析具體內存區域(堆、元空間、直接內存等)。

排查時可通過以下步驟:

1、確定 OOM 類型(通過錯誤日誌)。

2、使用工具分析(如 jstatjmapVisualVMMAT)。

3、調整 JVM 參數或優化代碼邏輯。

等被裁員在學習?趕緊的吧!

user avatar
0 users favorite the story!

Post Comments

Some HTML is okay.