一、出現內存溢出的幾種情況
內存溢出錯誤分為StackOverflowError和OutOfMemoryError,前者是棧中出現溢出,后者一般是堆或方法區出現溢出,簡稱OOM
1. 棧溢出 StackOverflowError
棧溢出一般都是因為沒有正確的結束遞歸導致的,無限遞歸導致超出棧內存(-Xss)限制時就會拋出StackOverflowError。這種情況直接根據異常信息定位到代碼位置進行修正即可。
2. 方法區溢出 OOM
當方法區中加載的類過多,比如通過動態代理生成很多代理類或者熱部署時熱加載了過多的類,多到超出方法區內存限制時(-XX:MaxMetaspaceSize),會拋出OutOfMemoryError。但這種情況一般也比較少見,如果真出現這種情況可以考慮增加MetaspaceSize,或者拆分服務,使得一個服務使用的類不超出限制。
3. 堆溢出 OOM
其實大部分OOM都是發生在堆區,當堆中存儲的對象過多,GC來不及回收或者回收不掉,沒有足夠空間創建新對象,就會拋出OutOfMemoryError。
java.lang.OutOfMemoryError: Java heap space
二、OOM排查思路
當堆區出現OOM時,就需要我們去進行排查,看什么對象把內存吃滿了
- 第一步:我們需要拿到發生OOM時堆區的內存快照heap dump,這里面保存了某一時刻堆中對象的情況。heap dump有兩種方式可以拿到。第一種就是我們預先在jvm進程啟動時開啟參數配置-XX:+HeapDumpOnOutOfMemoryError,-XX:HeapDumpPath=/usr/local/oom,當發生OOM時會自動生成heap dump保存在指定路徑下,這也是推薦的方式。第二種方式是如果jvm進程沒有被結束,可以用工具比如jdk自帶的jvisualvm手動獲取指定進程id的heap dump。
- 第二步:將拿到的heap dump導入到分析工具中,比如說MemoryAnalyzer,通過工具分析可以看到是哪些類型對象占用了大量內存及其GC引用鏈,還有錯誤棧等信息。
- 第三步:根據分析得到的信息到代碼中進行排查,如果是代碼邏輯有問題就改代碼,比如不恰當的強引用導致的內存泄漏。如果代碼邏輯沒問題,確實需要占這么多內存,那就考慮提升堆內存大小(-Xms -Xmx)。
參考:
https://blog.csdn.net/qq_31363843/article/details/117038001
https://blog.csdn.net/weixin_41010294/article/details/104009722