Java罕見內存溢出異常剖析與處理。本站提示廣大學習愛好者:(Java罕見內存溢出異常剖析與處理)文章只能為提供參考,不一定能成為您想要的結果。以下是Java罕見內存溢出異常剖析與處理正文
Java虛擬機標准劃定JVM的內存分為了好幾塊,好比堆,棧,法式計數器,辦法區等,而Hotspot jvm的完成中,將堆內存分為了三部門,重生代,老年月,耐久帶,個中耐久帶完成了標准中劃定的辦法區,而內存模子中分歧的部門都邑湧現響應的OutOfMemoryError毛病,接上去我們就離開來評論辯論一下。java.lang.OutOfMemoryError這個毛病我信任年夜部門開辟人員都有碰到過,發生該毛病的緣由年夜都出於以下緣由:
JVM內存太小、法式不周密,發生了過量的渣滓。
招致OutOfMemoryError異常的罕見緣由有以下幾種:
此毛病罕見的毛病提醒:
棧溢出(StackOverflowError)
棧溢出拋出java.lang.StackOverflowError毛病,湧現此種情形是由於辦法運轉的時刻棧的深度跨越了虛擬機允許的最年夜深度而至。湧現這類情形,普通情形下是法式毛病而至的,好比寫了一個逝世遞歸,就有能夠形成此種情形。 上面我們經由過程一段代碼來模仿一下此種情形的內存溢出。
import java.util.*; import java.lang.*; public class OOMTest{ public void stackOverFlowMethod(){ stackOverFlowMethod(); } public static void main(String... args){ OOMTest oom = new OOMTest(); oom.stackOverFlowMethod(); } }
運轉下面的代碼,會拋出以下的異常:
Exception in thread "main" java.lang.StackOverflowError at OOMTest.stackOverFlowMethod(OOMTest.java:6)
堆溢出(OutOfMemoryError:java heap space)
堆內存溢出的時刻,虛擬機遇拋出java.lang.OutOfMemoryError:Java heap space,湧現此種情形的時刻,我們須要依據內存溢出的時刻發生的dump文件來詳細剖析(須要增長-XX:+HeapDumpOnOutOfMemoryErrorjvm啟動參數)。湧現此種成績的時刻有能夠是內存洩漏,也有能夠是內存溢出了。
假如內存洩漏,我們要找出洩漏的對象是怎樣被GC ROOT援用起來,然後經由過程援用鏈來詳細剖析洩漏的緣由。
假如湧現了內存溢出成績,這常常是法式本生須要的內存年夜於了我們給虛擬機設置裝備擺設的內存,這類情形下,我們可以采取調年夜-Xmx來處理這類成績。
上面我們經由過程以下的代碼來演示一下此種情形的溢出:
import java.util.*; import java.lang.*; public class OOMTest{ public static void main(String... args){ List<byte[]> buffer = new ArrayList<byte[]>(); buffer.add(new byte[10*1024*1024]); } }
我們經由過程以下的敕令運轉下面的代碼:
java -verbose:gc -Xmn10M -Xms20M -Xmx20M -XX:+PrintGC OOMTest
法式輸出以下的信息:
[GC 1180K->366K(19456K), 0.0037311 secs] [Full GC 366K->330K(19456K), 0.0098740 secs] [Full GC 330K->292K(19456K), 0.0090244 secs] Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at OOMTest.main(OOMTest.java:7)
從運轉成果可以看出,JVM停止了一次Minor gc和兩次的Major gc,從Major gc的輸入可以看出,gc今後old區應用率為134K,而字節數組為10M,加起來年夜於了old generation的空間,所以拋出了異常,假如調劑-Xms21M,-Xmx21M,那末就不會觸發gc操作也不會湧現異常了。
經由過程下面的試驗其實也從正面驗證了一個結論:當對象年夜於重生代殘剩內存的時刻,將直接放入老年月,當老年月殘剩內存照樣沒法放下的時刻,觸發渣滓搜集,搜集後照樣不克不及放下就會拋出內存溢出異常了
耐久帶溢出(OutOfMemoryError: PermGen space)
我們曉得Hotspot jvm經由過程耐久帶完成了Java虛擬機標准中的辦法區,而運轉時的常量池就是保留在辦法區中的,是以耐久帶溢出有能夠是運轉經常量池溢出,也有能夠是辦法區中保留的class對象沒有被實時收受接管失落或許class信息占用的內存跨越了我們設置裝備擺設。當耐久帶溢出的時刻拋出java.lang.OutOfMemoryError: PermGen space。
我在任務能夠在以下幾種場景下湧現此成績。
應用一些運用辦事器的熱安排的時刻,我們就會碰到熱安排幾回今後發明內存溢出了,這類情形就是由於每次熱安排的後,本來的class沒有被卸載失落。
假如運用法式自己比擬年夜,觸及的類庫比擬多,然則我們分派給耐久帶的內存(經由過程-XX:PermSize和-XX:MaxPermSize來設置)比擬小的時刻也能夠湧現此種成績。
一些第三方框架,好比spring,hibernate都經由過程字節碼生成技巧(好比CGLib)來完成一些加強的功效,這類情形能夠須要更年夜的辦法區來存儲靜態生成的Class文件。
我們曉得Java中字符串常量是放在常量池中的,String.intern()這個辦法運轉的時刻,會檢討常量池中能否存和本字符串相等的對象,假如存在直接前往對常量池中對象的援用,不存在的話,先把此字符串參加常量池,然後再前往字符串的援用。那末我們便可以經由過程String.intern辦法來模仿一下運轉經常量區的溢出.上面我們經由過程以下的代碼來模仿此種情形:
import java.util.*; import java.lang.*; public class OOMTest{ public static void main(String... args){ List<String> list = new ArrayList<String>(); while(true){ list.add(UUID.randomUUID().toString().intern()); } } }
我們經由過程以下的敕令運轉下面代碼:
java -verbose:gc -Xmn5M -Xms10M -Xmx10M -XX:MaxPermSize=1M -XX:+PrintGC OOMTest
運轉後的輸出以下圖所示:
Exception in thread "main" java.lang.OutOfMemoryError: PermGen space at java.lang.String.intern(Native Method) at OOMTest.main(OOMTest.java:8)
經由過程下面的代碼,我們勝利模仿了運轉經常量池溢出的情形,從輸入中的PermGen space可以看出確切是耐久帶產生了溢出,這也驗證了,我們後面說的Hotspot jvm經由過程耐久帶來完成辦法區的說法。
OutOfMemoryError:unable to create native thread
最初我們在來看看java.lang.OutOfMemoryError:unable to create natvie thread這類毛病。 湧現這類情形的時刻,普通是上面兩種情形招致的:
法式創立的線程數跨越了操作體系的限制。關於Linux體系,我們可以經由過程ulimit -u來檢查此限制。
給虛擬機分派的內存過年夜,招致創立線程的時刻須要的native內存太少。我們都曉得操作體系對每一個過程的內存是無限制的,我們啟動Jvm,相當於啟動了一個過程,假設我們一個過程占用了4G的內存,那末經由過程上面的公式盤算出來的殘剩內存就是樹立線程棧的時刻可以用的內存。 線程棧總可用內存=4G-(-Xmx的值)- (-XX:MaxPermSize的值)- 法式計數器占用的內存 經由過程下面的公式我們可以看出,-Xmx 和 MaxPermSize的值越年夜,那末留給線程棧可用的空間就越小,在-Xss參數設置裝備擺設的棧容量不變的情形下,可以創立的線程數也就越小。是以假如是由於這類情形招致的unable to create native thread,那末要末我們增年夜過程所占用的總內存,或許削減-Xmx或許-Xss來到達創立更多線程的目標。
以上就是本文的全體內容,願望對年夜家的進修有所贊助,也願望年夜家多多支撐。