欢迎访问昆山宝鼎软件有限公司网站! 设为首页 | 网站地图 | XML | RSS订阅 | 宝鼎邮箱 | 后台管理


新闻资讯

MENU

软件开发知识
原文出处: Loh

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 的时候,昆山软件开发,处事会生成一个 java_pid$pid.hprof 二进制文件。

下面就是利用东西阐明这个 .hprof 文件来定位问题了。利用 Memory Analyzer (MAT) 来阐明该文件,结果如下:
问题都大  <a href=昆山软件定制开拓 同小异" src="/uploads/allimg/c180918/153H14HW53P-1T13.png" />

结果很吓人,什么鬼,什么对象,吃了 3.8G 的内存,我#%$#@#@#&^&^&#$….
打开 Leak Suspects» Leaks» Problem Suspect 1 看到如下详情:

问题都大  <a href=昆山软件定制开拓 同小异" src="/uploads/allimg/c180918/153H14I004060-21140.png" />

一开始大概没那么快找到问题,可是这个图已经很明明说明白问题,是 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 的方法来读取并写入文件流。然后发明,昆山软件开发,人家有一个 read line by line 的实现。可是切割上其实是有问题的,因为拿到一批 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 问题都是重启处事,治标不治本,照旧要多阐明问题并办理。