西安市政道橋建設(shè)公司網(wǎng)站sem是什么牌子
文章目錄
- 1. 前言
- 2. 堆內(nèi)存溢出
- 3. GC執(zhí)行異常
- 4. 元空間內(nèi)存溢出
- 5. 創(chuàng)建線程異常
- 6. 內(nèi)存交換問題
- 7. 數(shù)組長度過大
- 8. 系統(tǒng)誤殺異常
1. 前言
當系統(tǒng)異常產(chǎn)生了dump文件需要我們對其進行排查時,其本質(zhì)上考驗的是我們對于Java運行時內(nèi)存結(jié)構(gòu)的知識掌握是否牢固以及對業(yè)務(wù)代碼的熟悉程度。其次不要覺得這是一件很有技術(shù)含量高大上的事情,只要工具會用,對一般的異常有基本的判斷,大部分有點經(jīng)驗的開發(fā)都能勝任這個事情。
分析dump文件使用最多的便是Eclipse的MAT
工具或Java自帶的Visual VM
,更加推薦使用Visual VM
來進行排查,畢竟是官方的工具,只要安裝了JDK就會有,并且基本能滿足正常的排查要求。
很多開發(fā)平時很少有機會根據(jù)dump文件排查生產(chǎn)問題,因此總覺得這個事情比較虛,且沒有好的工具去實現(xiàn),其實Java官方提供的Visual VM
就能滿足大部分場景,基本足以解決日常需要。但前提是要學會使用導出Dump文件命令,以及在程序的啟動參數(shù)上增加異常自動生成dump文件的配置。
使用Visual VM排查時,使用類實例數(shù)、大小屬性和查看堆線程統(tǒng)計三個功能基本就能確定是哪些類或?qū)ο筮^多導致內(nèi)存溢出,最后再去代碼中看這些類在哪些地方會頻繁使用創(chuàng)建基本就能解決大部分問題。當我們在使用第三方框架時,一些框架的標識最好能夠在對象中體現(xiàn),這樣能夠幫助我們更快的更為是哪些功能有問題。
Visual VM的使用比較簡單,在這里不做過多闡述。
2. 堆內(nèi)存溢出
異常日志:
Java heap space
堆內(nèi)存異常是比較常見的,畢竟Java的所有數(shù)組和對象分配都是在堆上進行的。
一般堆內(nèi)存溢出常見于大量的創(chuàng)建對象卻沒有釋放,這種現(xiàn)象是比較容易排查的,只需要判斷某類對象是否過多即可。常見于重復(fù)代碼塊,或因某個事件頻繁觸發(fā)導致某個方法被頻繁調(diào)用,且方法里的對象一直沒被釋放導致內(nèi)存溢出。
3. GC執(zhí)行異常
異常日志:
GC overhead limit exceeded
當多次執(zhí)行垃圾收集的時間占用了CPU的98%,且GC回收的內(nèi)存少于2%,JVM就會拋出這個異常。但這個異常在部分情況下都是會被Java heap space
代替的,所以僅憑這個無法準確判斷出具體是什么問題,唯一能確定的就是當前堆內(nèi)存已經(jīng)被占滿,且在頻繁的執(zhí)行GC,和堆內(nèi)存溢出有相似之處。
處理方式一般和堆內(nèi)存異常類似,需要排查哪類對象占用了過多的內(nèi)存,在哪個代碼塊中存在頻繁的創(chuàng)建對象且不釋放的情況。
4. 元空間內(nèi)存溢出
異常日志:
Metaspace
從JDK8起,元空間代替了永久代,元空間一般存儲的數(shù)據(jù)為Class對象和常量對象等。
當出現(xiàn)這個問題需要著重排查新增的代理對象和字符串intern方法的使用。
5. 創(chuàng)建線程異常
異常日志:
Unable to create new native thread
每個機器內(nèi)核創(chuàng)建的線程數(shù)量是有限制的,當創(chuàng)建的線程數(shù)量過多時拋出該異常。
這類問題只要指定了線程名稱都很好排查,可以利用Visual VM查看堆轉(zhuǎn)儲上的線程就能看出來是哪些線程異常數(shù)量過多。
6. 內(nèi)存交換問題
異常日志:
Out of swap space?
操作系統(tǒng)一般都有虛擬內(nèi)存,當物理運行內(nèi)存不夠時會使用虛擬內(nèi)存,但當虛擬內(nèi)存都無法滿足JVM的要求時就會拋出該異常。
一般碰到這個問題需要檢查JVM的大小配置是否超過了機器本身配置,并檢查有沒有哪些對象創(chuàng)建數(shù)量異常導致內(nèi)存飆升。如果配置或代碼都沒問題,那最終只能升級機器、轉(zhuǎn)微服務(wù)開發(fā)或?qū)Τ绦驑I(yè)務(wù)進行拆分以滿足程序的性能要求。
7. 數(shù)組長度過大
異常日志:
Requested array size exceeds VM limit
出現(xiàn)的頻率較低,當數(shù)組的長度超出JVM的限制則拋該異常。
如果實際不需要這么長的數(shù)組則設(shè)置合適即可,如果需要這么長的數(shù)組則需要對數(shù)組進行分段處理。
8. 系統(tǒng)誤殺異常
異常日志:
Kill process or sacrifice child
當操作系統(tǒng)可用內(nèi)存極低的情況下會觸發(fā)killer操作殺掉部分線程,如果Java程序因為這個情況被誤殺則會拋出該異常。
一般原因是服務(wù)器運行了其它的程序,導致其它的程序占用過多內(nèi)存,觸發(fā)了killer機制,Java程序單獨部署可以避免這個問題。
生產(chǎn)問題千奇百怪,但只要把握住Java的運行時原理,大致判斷出不同的對象數(shù)據(jù)存儲在哪些地方,并根據(jù)堆對象統(tǒng)計大致判斷出問題所在,大部分生產(chǎn)問題都是可以解決的。
使用dump排查問題不是洪水猛獸。