java面試-談談你對OOM的理解


1、java.lang.StackOverflowError

  • 在一個函數中調用自己就會產生這樣的錯誤(棧溢出)
  • 發生區域:java虛擬機棧或本地方法棧
public class StackOverFlowErrorDemo {
    public static void main(String[] args) {
        stackOverFlowError();
    }

    public static void stackOverFlowError(){
        stackOverFlowError();
    }
}

2、java.lang.OutOfMemoryError: Java heap space

  • new 一個很大對象
  • 發生區域:java堆
/**
 * -Xms10m -Xmx10m
 */
public class JavaHeapSpaceDemo {

    static class  OOMObject{
    }

    public static void main(String[] args) {
        List<OOMObject> list = new ArrayList<>();
        while (true){
            list.add(new OOMObject());
        }
    }
}

3、java.lang.OutOfMemoryError: GC overhead limit exceeded

  • GC回收時間過長,超過98%的時間用來做GC,並且回收了不到2%的堆內存
/**
 * -Xms10m -Xmx10m -XX:+PrintGCDetails -XX:MaxDirectMemorySize=5m
 */
public class GCoverheadDemo {

    public static void main(String[] args) {
        int i = 0;
        List<String> list = new ArrayList<>();

        while (true) {
            list.add(String.valueOf(++i).intern());
        }
    }
}  

4、java.lang.OutOfMemoryError: Direct buffer memory

原因:直接內存不足

寫NIO程序經常使用ByteBuffer來讀取或寫入數據,這是一種基於通道與緩沖區的I/O方式

ByteBuffer.allocate() 分配JVM堆內存,屬於GC管轄范圍,需要拷貝所以速度相對較慢

ByteBuffer.allocateDirect() 分配操作系統本地內存,不屬於GC管轄范圍,不需要內存拷貝所以速度相對較快

/**
 * -Xms10m -Xmx10m -XX:+PrintGCDetails -XX:MaxDirectMemorySize=5m
 */
public class DirectBufferMemoryDemo {

    public static void main(String[] args) throws InterruptedException {
        System.out.println("maxDirectMemory : " + sun.misc.VM.maxDirectMemory() / 1024 / 1024 + "MB");
        TimeUnit.SECONDS.sleep(1);
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(6 * 1024 * 1024);
    }
}

5、java.lang.OutOfMemoryError : unable to create new native thread

  • 一個應用進程創建了多個線程,超過系統承載極限,Linux默認允許單個進程可以創建的線程數1024
/**
 * 一個應用進程創建了多個線程,超過系統承載極限,Linux默認是1024
 */
public class UnableCreateNewThreadDemo {
    public static void main(String[] args) {
        for (int i = 0; ; i++) {
            new Thread(() -> {
                try {
                    Thread.sleep(Integer.MAX_VALUE);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, String.valueOf(i)).start();
        }
    }
}  

linux系統下:

ulimit -u  --查看線程上限
cat /etc/security/limits.d/20-nproc.conf 

6、java.lang.OutOfMemoryError: Metaspace

java8使用Metaspace代替永久代,與永久代最大的區別是:元空間並不在虛擬機內存中,而是使用本地內存。  

永久代(java8使用Metaspace)存放的信息:

  • 虛擬機加載的類信息
  • 常量池
  • 靜態變量
  • 即時編譯后的代碼
/**
 * 不斷生成類往元空間推,類占據的空間總是會超過Metaspace的大小
 * -XX:MetaspaceSize=8m -XX:MaxMetaspaceSize=8m
 */
public class MetaspaceOOMDemo {

    static class OOMTest {
    }

    public static void main(String[] args) {
        int i = 0; //模擬計數多少次后發生了異常
        try {
            while (true) {
                i++;
                Enhancer enhancer = new Enhancer();
                enhancer.setSuperclass(OOMTest.class);
                enhancer.setUseCache(false);
                enhancer.setCallback(new MethodInterceptor() {
                    @Override
                    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                        return methodProxy.invokeSuper(o, args);
                    }
                });
                enhancer.create();
            }
        } catch (Throwable e) {
            System.out.println(i + "次后發送了異常");
            e.printStackTrace();
        }

    }
}

  

  

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM