Java OOM毫无疑问是开发人员常见并且及其痛恨的问题,但是任何服务的开发都没法避免OOM。因此,OOM的排查及定位是每个Java工程师都必备的技能。
所遇到的问题
在使用scala开发的一个web服务,在用户使用中,经常出现:java.lang.OutOfMemoryError: Java heap space。而且还束手无策,每次都只能重启服务解决。
准备
服务使用jetty发布的,先来看一下我这个服务的启动参数:
/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 &
排查
增加通过了参数-XX:+HeapDumpOnOutOfMemoryError
状语从句:-XX:HeapDumpPath
当在OOM
的时候,会服务在/opt/soft/heapdump
下生成一个java_pid$pid.hprof
二进制文件。
这个java_pid$pid.hprof
也可通过jmap
命令来即时生成:jmap -dump:format=b,file=java_pid$pid.hprof $pid
($ pid为java进程ID)
下面就是使用工具分析这个.hprof
文件来定位问题了。使用Memory Analyzer(MAT)
来分析该文件,效果如下:
效果很吓人,什么鬼,什么东西,吃了3.8G的内存,我#%KaTeX parse error: Double superscript at position 9: #@#@#&^&^̲&# …
打开泄漏嫌疑人»泄漏»问题可疑1看到如下详情:
一开始可能没那么快找到问题,但是这个图已经很明显说明了问题,的英文ArrayList
的内容太大,沾满了内存。但是你可能还不清楚具体那块代码导致,时候这个你可以点击那个ArrayList
在左侧栏看Attribute
。
然后一直鼠标右键into进去看里面的详情,最终是可以看内容的。
问题原因
问题排查到最后,ArrayList
看到的是里面存的全是ResponseBodyPart
,然后就想到了项目使用到Dispatch
请求下载结果文件,
于是乎去找到问题代码,错误代码如下:
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
})
看不出问题,感觉一切正常。翻源码会发现,res.getResponseBodyAsStream()
之前,将已经所有内容都存入一个ArrayList
当中了。哎,没用对啊。
解决办法
问题已经定位到,于是去了解了一下这个项目,该如何使用stream的方式来读取并写入文件流。然后发现,人家有一个逐行读取的实现。但是切割上其实是有问题的,因为拿到一批bytes之后,直接转成了string并用分隔符分割,
奈何内容里面有中文,出现乱码了。
最终,参考项目本身的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)
}))
总结
主要描述了分析问题的思路和方向,问题都大同小异,OOM总会有原因的,有原因肯定可以找到并解决.MAT这个分析工具很实用,内容很详细。以前遇到OOM问题都是重启服务,治标不治本,还是要多分析问题并解决。
(想自学习编程的小伙伴请搜索圈T社区,更多行业相关资讯更有行业相关免费视频教程等待你来学习。完全免费哦! )