中文字幕在线观看,亚洲а∨天堂久久精品9966,亚洲成a人片在线观看你懂的,亚洲av成人片无码网站,亚洲国产精品无码久久久五月天

Java 內(nèi)存溢出排查

2018-09-17    來源:importnew

容器云強(qiáng)勢上線!快速搭建集群,上萬Linux鏡像隨意使用

Java OOM 毫無疑問是開發(fā)人員常見并且及其痛恨的問題,但是任何服務(wù)的開發(fā)都沒法避免 OOM。 因此,OOM 的排查及定位是每個 Java 工程師都必備的技能。

所遇到的問題

在使用 scala 開發(fā)的一個 web 服務(wù),在用戶使用中,經(jīng)常出現(xiàn):?java.lang.OutOfMemoryError: Java heap space?。而且還束手無策,每次都只能重啟服務(wù)解決。

準(zhǔn)備

服務(wù)使用 jetty 發(fā)布的,先來看一下我這個服務(wù)的啟動參數(shù):

/opt/soft/jdk/jdk1.7.0_40/bin/java \
  -server -Xmx4G -XX:MaxPermSize=1024M -XX:PermSize=256M \
  -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:-CMSConcurrentMTEnabled -XX:CMSInitiatingOccupancyFraction=65 -XX:+CMSParallelRemarkEnabled \
  -XX:+HeapDumpOnOutOfMemoryError \
  -XX:HeapDumpPath=/opt/soft/heapdump/ \
  -Dscala.concurrent.context.numThreads=500 \
  -Dscala.concurrent.context.maxThreads=500 \
  -Dfile.encoding=UTF-8 -jar start.jar >> log 2>&1 &

排查

通過增加了參數(shù)?-XX:+HeapDumpOnOutOfMemoryError?和?-XX:HeapDumpPath?當(dāng)在 OOM 的時候,服務(wù)會生成一個?java_pid$pid.hprof?二進(jìn)制文件。

下面就是使用工具分析這個?.hprof?文件來定位問題了。使用?Memory Analyzer (MAT)?來分析該文件,效果如下:

效果很嚇人,什么鬼,什么東西,吃了 3.8G 的內(nèi)存,我#%$#@#@#&^&^&#$….
打開 Leak Suspects? Leaks? Problem Suspect 1 看到如下詳情:

一開始可能沒那么快找到問題,但是這個圖已經(jīng)很明顯說明了問題,是?ArrayList?的內(nèi)容太大,沾滿了內(nèi)存。但是你可能還不清楚具體那塊代碼導(dǎo)致,這個時候你可以點擊那個?ArrayList?在左側(cè)欄看?Attribute
然后一直鼠標(biāo)右鍵?into?進(jìn)去看里面的詳情,最終是可以看內(nèi)容的。

問題原因

問題排查到最后,看到的是?ArrayList?里面存的全是?ResponseBodyPart, 然后就想到了項目使用到?Dispatch?請求下載結(jié)果文件,
于是乎去找到問題代碼,錯誤代碼如下:

val outputReq = dispatch.url(url) / "task" / "output" / id
val outputFuture = Http(outputReq > { res =>
  val out = new FileOutputStream(outputFile(taskId), true)
  IOUtils.copy(res.getResponseBodyAsStream(), out)
  out.close
})

看不出問題,感覺一切正常。翻源碼會發(fā)現(xiàn),res.getResponseBodyAsStream()?之前,已經(jīng)將所有內(nèi)容都存入一個?ArrayList?當(dāng)中了。哎,沒用對啊。

解決辦法

問題已經(jīng)定位到,于是去了解了一下這個項目,該如何使用 stream 的方式來讀取并寫入文件流。然后發(fā)現(xiàn),人家有一個?read line by line?的實現(xiàn)。但是切割上其實是有問題的,因為拿到一批 bytes 之后,直接轉(zhuǎn)成了 string 并用分隔符分割,
奈何內(nèi)容里面有中文,出現(xiàn)亂碼了。

最終,參考項目本身的?as.stream.Lines?寫了一個?as.stream.Bytes?來通過 bytes 邊讀邊寫,如下:

val bos = new BufferedOutputStream(new FileOutputStream("/tmp/file.txt", true))
val outputFuture = Http(outputReq > as.stream.Bytes(bytes => {
  bos.write(bytes)
}))

總結(jié)

主要描述了分析問題的思路和方向,問題都大同小異,OOM 總會有原因的,有原因肯定可以找到并解決。MAT 這個分析工具很實用,內(nèi)容很詳細(xì)。以前遇到 OOM 問題都是重啟服務(wù),治標(biāo)不治本,還是要多分析問題并解決。

標(biāo)簽: isp 代碼

版權(quán)申明:本站文章部分自網(wǎng)絡(luò),如有侵權(quán),請聯(lián)系:west999com@outlook.com
特別注意:本站所有轉(zhuǎn)載文章言論不代表本站觀點!
本站所提供的圖片等素材,版權(quán)歸原作者所有,如需使用,請與原作者聯(lián)系。

上一篇:如果非得了解下 git 系統(tǒng)… – 實踐篇

下一篇:Java 中處理異常的 9 個最佳實踐