本来要写一篇文章,发现该博主的内容太好了,就直接黏贴过来了。
前言
在平时开发、测试过程中、甚至是生产环境中,有时会遇到OutOfMemoryError,Java堆溢出了,这表明程序有严重的问题。我们需要找造成OutOfMemoryError原因。一般有两种情况:
1、内存泄露,对象已经死了,无法通过垃圾收集器进行自动回收,通过找出泄露的代码位置和原因,才好确定解决方案;
2、内存溢出,内存中的对象都还必须存活着,这说明Java堆分配空间不足,检查堆设置大小(-Xmx与-Xms),检查代码是否存在对象生命周期太长、持有状态时间过长的情况。
以上是处理Java堆问题的思路,具体是怎么进行分析,这里介绍的是使用Eclipse Memory Analyzer tool(MAT)工具分析的过程。
2、内存溢出,内存中的对象都还必须存活着,这说明Java堆分配空间不足,检查堆设置大小(-Xmx与-Xms),检查代码是否存在对象生命周期太长、持有状态时间过长的情况。
以上是处理Java堆问题的思路,具体是怎么进行分析,这里介绍的是使用Eclipse Memory Analyzer tool(MAT)工具分析的过程。
生成dump文件
MAT安装与介绍
![点击查看原始大小图片](http://dl.iteye.com/upload/attachment/0066/6787/84bb3118-17b2-366c-923f-8fc3fb03705b.png)
![点击查看原始大小图片](http://dl.iteye.com/upload/attachment/0066/6785/970df6ba-575b-3fb9-9a0d-4cc34fcead6b.png)
![点击查看原始大小图片](http://dl.iteye.com/upload/attachment/0066/6796/ef17e5cd-d7ec-3d8b-a07b-70c65fc7783e.png)
![点击查看原始大小图片](http://dl.iteye.com/upload/attachment/0066/6791/6be4bf4e-d7f6-33f6-a5b1-2aef78d7ab84.png)
通过Leak Suspects的
Problem Suspect 1点击【
Details »】,
如下图如下图所示的上下文菜单中选择 List objects -> with outgoning references, 查看ThreadLocal都应用了些什么对象。
![点击查看原始大小图片](http://dl.iteye.com/upload/attachment/0066/6794/77779fa4-20d9-329e-b7fb-d1117d494592.png)
现在看到ThreadLocal中引用的对象如下图:
是dao对象
ps:该dao对象包含一个轻量级的ORM关系内容,所以Retained size比较大。
![点击查看原始大小图片](http://dl.iteye.com/upload/attachment/0066/6793/9cf2d100-bf3f-394c-b86f-5577707d7778.png)
下面继续查看dao的gc ROOT
如下图所示的上下文菜单中选择 Path To GC Roots -> exclude weak references, 过滤掉弱引用,因为在这里弱引用不是引起问题的关键。
![点击查看原始大小图片](http://dl.iteye.com/upload/attachment/0066/6803/f0a604d4-506f-37e9-a88e-333c730be019.png)
从下图中,可以看到在org.quartz.simpl.SimpleThreadPool中保存了daos的引用。所以可以得出是是因为定时器在运行的过程中持有大量的Daos对象应起了内存泄露。为什么会有那么多的Daos呢,Daos不是一个无状态的单例的、可以重用的吗?继续查看spring配置文件发现Daos的bean配置成scope="prototype",导致定时任务又是每次调用都生产新的Daos实例。由于是Daos是无状态的,修改为单例的,问题解决。
![点击查看原始大小图片](http://dl.iteye.com/upload/attachment/0066/6801/c9820b9e-1f42-30cc-9d32-c3c390288b3f.png)
以上是通过MAT分析Tomcat应用程序,找到内存泄露的原因,并解决。