背景介绍
新建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
来源:oschina
链接:https://my.oschina.net/u/163737/blog/715065