OOM三種類型


OOM的三種類型:

堆OOM


/** * -Xmx1g -XX:+PrintGCDetails -XX:MaxDirectMemorySize=100m * * @param args */ public static void main(String[] args) { ArrayList<byte[]> arrayList = new ArrayList<>(); for (int i = 0; i < 1024; i++) { arrayList.add(new byte[1024 * 1024 * 2]); } } 

運行結果:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at com.Test.main(Test.java:15)

解決方法: 增大Xmx值 使用MAT,JProfile等工具進行代碼分析與優化


直接內存OOM

 /** * -Xmx1g -XX:+PrintGCDetails -XX:MaxDirectMemorySize=100m * @param args */ public static void main(String[] args) { for (int i = 0; i < 2048; i++) { ByteBuffer.allocateDirect(1024 * 1024*2); System.out.println(i); //System.gc(); } } 

運行結果: 直接內存設置為2M,超過100M時,進行回收

解決方法: 增大MaxDirectMemorySize的值


過多線程導致的OOM

 /** * -Xmx1g -XX:+PrintGCDetails -XX:MaxDirectMemorySize=100m -Xss:指定棧空間大小 * * @param args */ public static void main(String[] args) { for (int i = 0; i <1500 ; i++) { new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); } } 

運行結果: OOM unable to create native thread

解決方法: 減少線程數、或減少堆空間與線程空間


永久(Pern)溢出

永久區是存儲類元數據的區域

/** * -Xmx1g -XX:+PrintGCDetails * * @param args */ public static void main(String[] args) { for (int i = 0; i < 1000000000; i++) { Integer integer = new Integer("1" + new StringBuffer(1)); System.out.println(new ArrayList<>()); } } 

運行結果: OOM Permgen sace 解決方法:

  • 增大MaxPremSize的值
  • 減少系統需要的類的數量
  • 使用ClassLoader合理裝載類,並進行回收

GC效率低下引起的OOM

判斷GC引起OOM的條件

  1. 花在GC上的時間是否超過了98%
  2. 老年代釋放的內存是否小於2%
  3. Eden區釋放的內存是否小於2%
  4. 是否連續5次GC都出現了上述幾種情況

關閉OOM可以通過參數:-XX:-UseGCOverheadLimit 進行設置

String常量池因其的OOM


 /** * -Xmx5m -XX:MaxPermSize5m【JDK<1.6】 * * @param args */ public static void main(String[] args) { List<String> list = new ArrayList<>(); int i = 0; while (true) { list.add(String.valueOf(i++).intern()); } } 

運行結果: JDK1.6 :Perm space JDK1.7 :heap space

【注】

 /** *String.intern()方法返回字符串常量池引用,但不一定每時每刻都返回一樣,可能垃圾回收后重新放入常量池 * * @param args */ public static void main(String[] args) { System.out.println(System.identityHashCode((args[0] + Integer.toString(0))));//字符本身hash System.out.println(System.identityHashCode((args[0] + Integer.toString(0)).intern()));//常量池引用 System.gc();//未gc前常量池引用相同 System.out.println(System.identityHashCode((args[0] + Integer.toString(0)).intern()));//常量池引用 } 

淺堆和深堆

淺堆(shallow heap):一個對象結構所占的內存大小,對象包括屬性和對象頭、對象引用等。

如String對象,其結構包括:
類型 大小
int hash32 0
int hash 0
ref value c://...

其中2個int8字節 對象引用4字節 對象頭8字節 按照8字節對齊,則對象淺堆共24字節

深堆(retained heap):一個對象被GC回收后,可以真實釋放的內存大小。即對象所持有的對象和包括對象自身的所有的淺堆的大小之和。

從圖中可以看出對象A的淺堆大小為A本身,對象A的實際大小為對象A、對象B、對象C、對象D的淺堆大小之和,對象A的深堆大小為對象A和對象C,因為對象B和對象D同時也被對象E所引用


免責聲明!

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



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