內(nèi)存溢出(Out Of Memory
,簡(jiǎn)稱(chēng)OOM
)是指應(yīng)用系統(tǒng)中存在無(wú)法回收的內(nèi)存或使用的內(nèi)存過(guò)多,最終使得程序運(yùn)行要用到的內(nèi)存大于能提供的最大內(nèi)存。此時(shí)程序就運(yùn)行不了,系統(tǒng)會(huì)提示內(nèi)存溢出,有時(shí)候會(huì)自動(dòng)關(guān)閉軟件,重啟電腦或者軟件后釋放掉一部分內(nèi)存又可以正常運(yùn)行該軟件,而由系統(tǒng)配置、數(shù)據(jù)流、用戶代碼等原因而導(dǎo)致的內(nèi)存溢出錯(cuò)誤,即使用戶重新執(zhí)行任務(wù)依然無(wú)法避免
其實(shí)很簡(jiǎn)單,在 Java
中,那就是 Out Of Memory
,導(dǎo)致了不合理的 GC
,那么如何去定位這個(gè)內(nèi)存溢出的呢?實(shí)際上如果是大公司,那么會(huì)有專(zhuān)業(yè)的運(yùn)維人員去定位哪些程序?qū)е铝藘?nèi)存溢出,但是如果要是沒(méi)有專(zhuān)業(yè)的運(yùn)維人員,那么你自己就得學(xué)會(huì)怎么去定位這個(gè)內(nèi)存溢出了。
如何定位內(nèi)存溢出
一、定位占用CPU
最高的服務(wù) 1、先找到cpu占用比較高的進(jìn)程:top``-c
進(jìn)去后按Shift+P
鍵
一般異常的進(jìn)程cpu
的占用會(huì)很高,記錄下這進(jìn)程的PID
2、查看指定進(jìn)程cpu
情況:top -cp PID
查看此進(jìn)程占用cpu
最高的線程,記錄下線程的ppid
也可以將相關(guān)信息保存下來(lái):top -Hp PID -o %CPU -n 1 >cpu.txt
到此,我們就找到的最占用cpu
的進(jìn)程以及相關(guān)線程。
3.如果你已經(jīng)知道是你們的 Java
程序?qū)е铝藘?nèi)存溢出,那么我們就得學(xué)會(huì)分析日志,一般在 Out Of Memory
的上方,我們都會(huì)有各種日志的輸出,來(lái)標(biāo)志現(xiàn)在這個(gè)時(shí)間點(diǎn),我們的程序執(zhí)行了什么操作,導(dǎo)致了我們的這個(gè)內(nèi)存溢出,分析到這里,就輪到看代碼了。
檢查的內(nèi)容大致都有哪些地方呢?
在一個(gè)項(xiàng)目中,使用兩個(gè)數(shù)據(jù)庫(kù)連接,其中專(zhuān)用于發(fā)送短信的數(shù)據(jù)庫(kù)連接使用 DBCP
連接池管理,用戶為不將短信發(fā)出,有意將數(shù)據(jù)庫(kù)連接用戶名改錯(cuò),使得日志中有許多數(shù)據(jù)庫(kù)連接異常的日志,一段時(shí)間后,就出現(xiàn) OutOfMemory
錯(cuò)誤。經(jīng)分析,這是由于 DBCP
連接池 BUG
引起的,數(shù)據(jù)庫(kù)連接不上后,沒(méi)有將連接釋放,最終使得D BCP
報(bào)OutOfMemory
錯(cuò)誤。
上面這是一個(gè)簡(jiǎn)單的例子,比如還有其他的,代碼中是否有死循環(huán)或遞歸調(diào)用。是否有大循環(huán)重復(fù)產(chǎn)生新對(duì)象實(shí)體。檢查對(duì)數(shù)據(jù)庫(kù)查詢中,是否有一次獲得全部數(shù)據(jù)的查詢。一般來(lái)說(shuō),如果一次取十萬(wàn)條記錄到內(nèi)存,就可能引起內(nèi)存溢出。這個(gè)問(wèn)題比較隱蔽,在上線前,數(shù)據(jù)庫(kù)中數(shù)據(jù)較少,不容易出問(wèn)題,上線后,數(shù)據(jù)庫(kù)中數(shù)據(jù)多了,一次查詢就有可能引起內(nèi)存溢出。因此對(duì)于數(shù)據(jù)庫(kù)查詢盡量采用分頁(yè)的方式查詢。
檢查List
、MAP
等集合對(duì)象是否有使用完后,未清除的問(wèn)題。List
、MAP
等集合對(duì)象會(huì)始終存有對(duì)對(duì)象的引用,使得這些對(duì)象不能被GC
回收。
比如我們這次內(nèi)存溢出,就是因?yàn)橐粋€(gè)很簡(jiǎn)答的導(dǎo)入功能,因?yàn)榉?wù)器給服務(wù)拆分的內(nèi)存只有2G,而程序也沒(méi)有專(zhuān)門(mén)的去處理,實(shí)施導(dǎo)入數(shù)據(jù)的時(shí)候,直接把100w的空數(shù)據(jù)從Excel
中直接導(dǎo)入了,結(jié)果,直接導(dǎo)致了內(nèi)存溢出。那么我們應(yīng)該怎么去處理這個(gè)呢?
其實(shí)我們的比較簡(jiǎn)單,就是直接限定了文件的大小,因?yàn)?code>Excel 雖然很大,但是有數(shù)據(jù)量的就那么幾百行,100w行,都是空行數(shù)據(jù),還都識(shí)別了,所以處理方式就那么幾種,限制文件大小,限制讀取數(shù)據(jù)的時(shí)候不讀空行,因?yàn)楫吘箖?nèi)存大小是已經(jīng)不允許我們做修改了,只能通過(guò)這個(gè)代碼業(yè)務(wù)層面來(lái)處理這個(gè)了。
如何解決內(nèi)存溢出呢?
內(nèi)存溢出的解決方案:
第一步,修改JVM
啟動(dòng)參數(shù),直接增加內(nèi)存。(-Xms
,-Xmx
參數(shù)一定不要忘記加。)
第二步,檢查錯(cuò)誤日志,查看OutOfMemory
錯(cuò)誤前是否有其它異?;蝈e(cuò)誤。
第三步,對(duì)代碼進(jìn)行走查和分析,找出可能發(fā)生內(nèi)存溢出的位置。
重點(diǎn)排查以下幾點(diǎn):
1.檢查對(duì)數(shù)據(jù)庫(kù)查詢中,是否有一次獲得全部數(shù)據(jù)的查詢。一般來(lái)說(shuō),如果一次取十萬(wàn)條記錄到內(nèi)存,就可能引起內(nèi)存溢出。這個(gè)問(wèn)題比較隱蔽,在上線前,數(shù)據(jù)庫(kù)中數(shù)據(jù)較少,不容易出問(wèn)題,上線后,數(shù)據(jù)庫(kù)中數(shù)據(jù)多了,一次查詢就有可能引起內(nèi)存溢出。因此對(duì)于數(shù)據(jù)庫(kù)查詢盡量采用分頁(yè)的方式查詢。
2.檢查代碼中是否有死循環(huán)或遞歸調(diào)用。
3.檢查是否有大循環(huán)重復(fù)產(chǎn)生新對(duì)象實(shí)體。
4.檢查List
、MAP
等集合對(duì)象是否有使用完后,未清除的問(wèn)題。List
、MAP
等集合對(duì)象會(huì)始終存有對(duì)對(duì)象的引用,使得這些對(duì)象不能被GC
回收。
第四步,使用內(nèi)存查看工具動(dòng)態(tài)查看內(nèi)存使用情況
一般的,使用的工具有很多,MAT
(Memory Analyzer Tool) 這個(gè)工具是一個(gè)比較好用的分析內(nèi)存的工具,還有 jmeter
這個(gè)壓力測(cè)試工具,可對(duì)特定接口進(jìn)行壓測(cè),分析tps、響應(yīng)時(shí)間、CPU、內(nèi)存等性能指標(biāo)。
JConsole
、JVisualVM
jdk 自帶可視化工具,可監(jiān)控CPU
、內(nèi)存、線程等狀況。
-
cpu
+關(guān)注
關(guān)注
68文章
10902瀏覽量
213007 -
內(nèi)存
+關(guān)注
關(guān)注
8文章
3055瀏覽量
74327 -
程序
+關(guān)注
關(guān)注
117文章
3795瀏覽量
81406 -
數(shù)據(jù)流
+關(guān)注
關(guān)注
0文章
121瀏覽量
14437 -
線程
+關(guān)注
關(guān)注
0文章
505瀏覽量
19756
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論