Java内存溢出如何处理

巧了我就是萌 提交于 2019-12-02 14:45:43

背景介绍

新建Java对象时会在JVM的Heap中分配内存,对象不可达时其内存会被JVM GC回收,
但是当Heap中没有多余内存可供分配时,就会报OutOfMemory错误(以下简称OOM):

严重: Unexpected death of background thread ContainerBackgroundProcessor[StandardEngine[Catalina]]
java.lang.OutOfMemoryError: Java heap space
	at org.apache.catalina.startup.HostConfig.checkResources(HostConfig.java:1379)

解决方法

解决方式很简单——加大Heap:

set JAVA_OPTS=-Dfile.encoding=UTF-8 -Xms1024m -Xmx2048m -XX:PermSize=256m -XX:MaxPermSize=512m

但是这不是根本解决之道:

  • 首先,Heap也不是越大越好,太大了以后GC会损害性能;
  • 其次,内存也是有成本的;
  • 最重要的,OOM有可能意味着系统中存在缺陷,不管Heap加多大,早晚还是有一天会被用光!

根本解决之道——通过Profilling找到问题根源

OOM通常是由于内存被不合理的使用,比如:

  • 查询数据库返回大量结果没有分页;
  • 读取大文件到内存中;

但是OOM错误不像其它报错那样容易排查,因为没有Stacktrace可供查看。
要找出内存被过度使用的原因,必须去“看”OOM时JVM Heap中的状况——哪些Class的Object占用了过多的内存——Profilling

Oracle JDK已经自带了很好用的Profilling工具:

  • JMX监控

    setclasspath.bat中添加
    【set CATALINA_OPTS=-Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.port=1010 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false】
    命令行【jconsole】打开界面,连接tomcat进程,远程端口1010,可以查看内存水位、线程池等。

  • jmap和jvisualvm

jconsole能看到的信息比较有限,无法排查出耗掉内存的元凶,
还需借助jmap来把JVM Heap“转储”到文件,然后通过jvisualvm来analysis:
当你的服务OOM了,找到jvm进程id,然后命令行【jmap -heap:format=b pid】生成heap.bin;
然后命令行【jvisualvm】打开分析器,加载heap.bin,查看内存状态,看看是哪个家伙把内存吃光了;
如下图:ParamTreePaymentTerm有3852个实例,消耗了593K的Heap内存:

根据问题原因对应优化代码,并按照需要给jvm分配相应内存。

常用 Java Profiling 工具的分析与比较参考http://www.oschina.net/question/12_10515

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!