1. 程式人生 > >OOM異常 Java內存溢出

OOM異常 Java內存溢出

持久 線程 ace ide profiler hotspot swe perm epg

1.OutOfMemoryError

  • 拋出異常後先確定是堆溢出還是棧溢出
  • 內存泄漏: Memory Leak 申請到內存之後無法 釋放 申請到的內存,造成這種情況的就是某個對象一直被引用這。
  • 內存溢出:Memory OverFlow :申請內存時沒有足夠的空間可以使用,拋出OOM。
  • 可以使用 Eclipse Memory Analyzer 或者 JProfiler(IDEA)分析內存是否泄漏
  1. 堆溢出:java.lang.OutOfMemoryError: Java heap space

    1. -Xms 設置初始堆的大小,設置為20MB -Xms20m
    2. -Xmx設置最大堆的大小
  2. 虛擬機棧溢出和本地方法棧溢出

    1. HotSpot 虛擬機並不區分虛擬機棧和本地方法棧他兩適合在一起的所以 用來設置本地方法棧大小的-Xoos並沒有什麽效果。
    2. -Xss 設置棧容量大小
    3. 棧可以拋出2種異常
      • StackOverflowError 線程請求的棧深度大於虛擬機所允許的最大深度。
      • OutOfMemoryError 擴展棧時無法申請到足夠的內存
    4. 操作系統分配給每個進程的內存是有限的,如32位win給進程分配的是2G,棧內存 = 2GB - 堆Xmx - 方法區 MaxPermSize
    5. 線程越多分配的棧內存就越少,每個線程分配的棧容量就越大線程就越少,容易把剩下的內存耗盡。
    6. jvm默認情況下棧深度平均在1000-2000間(棧幀個數即方法數量),如果不能更換更高位數的操作系統也不能減少線程數量,那麽可以通過減少堆的最大容量讓出一部分內存來給棧,避免棧內存溢出。
  3. 方法區和運行時常量池溢出

    1. OutOfMemoryError:PermGen space 運行時常量池在方法區中他兩都會拋出此異常。
    2. -XX:PermSize 方法區初始值大小
    3. -XX:MaxPermSize 方法區最大值
    4. 由於1.8 去永久帶 而加入了 Metaspace 元空間 所以上面的配置 1.8 開始就不能失效了
    5. -XX:MetaspaceSize 元空間大小, -XX:MaxMetaspace元空間最大值。
  4. 本機直接內存溢出

    1. -XX: MaxDirectMemorySize 可以指定最大值,如果不指定默認和堆一樣大。
    2. 由於直接內存不在堆裏,它是供NIO使用的所以拋出OOM異常後通過jvm內存檢測工具 在Heap Dump中沒有明顯錯誤,但是Dump文件很小就可以考慮直接內存溢出

知識點:

  1. string.intern()是一個本地方法,它只 返回字符串常量池中唯一的那個string。
            String st1 = new StringBuilder("Mi").append("bloom").toString(); // 初始字符串常量池不存在Mibloom  
            String st2 = new StringBuilder("ja").append("va").toString();// 初始字符串常量池存在java  
            System.out.println(st1.intern() == st1);// 1.6為 false,1.7為true
            System.out.println(st2.intern() == st2);//始終為true
    1. 如果字符串常量池中已經包含了一個等於此string對象的符號,則返回字符串常量池中的對象。
    2. 如果字符串常量池中沒有則將string加入字符串常量池並返回字符串常量池中的對象,此加入操作在jdk1.6 和1.7 中有所不同。
    3. 1.6中首次出現的string加入字符串常量池中的是直接復制到永久代中的字符串常量池中,所以地址會發生變化。
    4. 1.7開始 首次出現的string加入字符串常量池是復制string的引用到常量池中,所以地址不會發生變化。1.7開始 字符串常量池被移到了堆中。
  2. JVM 其他配置參數
    //常見配置匯總 
    //堆設置 
    -Xms:初始堆大小 
    -Xmx:最大堆大小 
    -XX:NewSize=n:設置年輕代大小 
    -XX:NewRatio=n:設置年輕代和年老代的比值.如:為3,表示年輕代與年老代比值為1:3,年輕代占整個年輕代年老代和的1/4 
    -XX:SurvivorRatio=n:年輕代中Eden區與兩個Survivor區的比值.註意Survivor區有兩個.如:3,表示Eden:Survivor=3:2,一個Survivor區占整個年輕代的1/5 
    -XX:MaxPermSize=n:設置持久代大小
    //收集器設置 
    -XX:+UseSerialGC:設置串行收集器 
    -XX:+UseParallelGC:設置並行收集器 
    -XX:+UseParalledlOldGC:設置並行年老代收集器 
    -XX:+UseConcMarkSweepGC:設置並發收集器
    //垃圾回收統計信息 
    -XX:+PrintGC 
    -XX:+PrintGCDetails 
    -XX:+PrintGCTimeStamps 
    -Xloggc:filename
    //並行收集器設置 
    -XX:ParallelGCThreads=n:設置並行收集器收集時使用的CPU數.並行收集//線程數. 
    -XX:MaxGCPauseMillis=n:設置並行收集最大暫停時間 
    -XX:GCTimeRatio=n:設置垃圾回收時間占程序運行時間的百分比.公式為1/(1+n)
    //並發收集器設置 
    -XX:+CMSIncrementalMode:設置為增量模式.適用於單CPU情況. 
    -XX:ParallelGCThreads=n:設置並發收集器年輕代收集方式為並行收集時,使用的CPU數.並行收集線程數.

OOM異常 Java內存溢出