Java棧內存堆內存溢出及相關JVM參數配置總結


一:Java里內存溢出分為棧內存溢出和堆內存溢出,不過一般而言我們說某個Java應用發生了內存溢出就是指堆內存溢出,即OOM,對應java.lang.OutOfMemoryError這個異常(錯誤);而棧內存溢出則是java.lang.StackOverflowError異常;

 

二:Java里每個線程都有一個棧空間(棧內存),可以通過JVM參數-Xss256k來配置線程棧空間大小;而線程棧空間里還有棧幀的概念,線程上每調用一個方法都會壓入一個棧幀(棧幀里存儲該方法里的棧變量),比如主線程執行main方法,那么main方法就是主線程的一個棧幀,在main方法里再調用test()方法,則主線程又會壓入新的棧幀來對應test()方法;當執行完畢方法返回后,比如test()方法執行完畢,那么線程會將對應的棧幀彈出,即釋放由該方法創建的變量占用的棧內存;

 

三:正常情況下是不太可能出現棧內存溢出的,因為棧幀的存在,以及一個方法基本上都不會成千上萬行,再加上存儲在棧上的數據基本上都是變量類型,如int,double,引用之類的(就占幾個字節),所以出現了棧內存溢出基本上都和遞歸函數有關;

在JVM里沒有相關的配置參數來設置棧內存溢出后的操作,而且也是不需要的,因為StackOverflowError異常棧里就已經能夠知道是哪些函數/方法導致了棧內存溢出(每個線程都有一個棧空間);

而堆內存溢出則不能夠通過OutOfMemoryError異常棧里來判斷是哪些方法導致的,舉個例子-Xmx2g的應用,然后A線程里的一些方法通過創建變量使用了1g,B線程里的一些方法占用了0.95g,然后此時C線程執行方法里創建了部分對象導致超過了2g

產生OOM,那么異常顯然是在C線程方法里拋出來的,所以異常棧信息也都是C線程里的一些方法,但是顯然我們不能斷言說主要是C線程里的方法導致了OOM;

 

四:堆內存溢出的情況是創建了大量的類,而這些類都還在使用,使得gc回收時無法回收,最終持續的創建對象就造成了堆內存溢出;

我們可以通過配置JVM參數來實現當出現OutOfMemoryError錯誤的時候,dump對應的堆內存使用數據,然后通過jvisualvm.exe這個jdk工具來分析產生OOM時的各個類的創建數量,占用內存,所屬線程等信息來分析是哪里導致的OOM;

配置參數為:-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/opt/apps/xx-service;第一個表示產生了OOM要dump出一個.hprof文件,第二個是dump的該文件存放在哪個目錄;

還可以通過配置-XX:OnOutOfMemoryError="/opt/apps/xx-service/xx.sh"來實現當產生了OOM時,在拋出此OOM之前執行后面的命令/腳本,然后拋出OOM;

還可以通過配置-XX:+ExitOnOutOfMemoryError來實現當出現了OOM會自動關閉程序,注意如果和上面的一起配置,這個優先級是最低的,即會dump文件,也會執行命令后才關閉應用;


免責聲明!

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



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