Java内存溢出如何处理

背景介绍

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

严重: 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

可是这不是根本解决之道:apache

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

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

OOM一般是因为内存被不合理的使用,好比:tomcat

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

可是OOM错误不像其它报错那样容易排查,由于没有Stacktrace可供查看。
要找出内存被过分使用的缘由,必须去“看”OOM时JVM Heap中的情况——哪些Class的Object占用了过多的内存——Profillingjvm

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分配相应内存。spa

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

相关文章
相关标签/搜索