在最近的工作中,通过JProfiler解决了一个内存泄漏的问题,现将检测的步骤和一些分析记录下来,已备今后遇到相似问题时可以作为参考。

运行环境:

Tomcat6,jdk6,JProfiler8

内存泄漏的现象:

1. 在服务器中执行某些批量操作的时候,发现内存只升不降;就算gc后,内存也不能被完全释放;
2. 除非重启tomcat服务器,内存永远不会被释放,反复执行这些操作,会导致无可用内存,tomcat死掉;

使用JProfiler检查内存泄漏的步骤:

1. 初始化检验环境:

切换到“Live Memory-->All Objects”标签,可以看到当前tomcat中的对象情况。

在执行操作前,需要先运行“Run GC”,使jvm进行内存回收,清理无效的对象;

为了便于比较内存的增长情况,可以点击"Mark Current"按钮,来将当前内存使用情况作为参照;

点击后会显示“Difference”列,该列会列出对象数量的变化和变化比率;

2.打开内存记录:

点击“Start Recordings”按钮,开始记录。执行这步的主要目的是为下面“Heap Walker”,设置一个监控区间;如果不记录的话,“Heap Walker”将分析jvm虚拟机的所有内存,即耗时又不能准确的发现内存泄漏的原因。

3. 执行操作,执行gc;

执行会引起内存泄漏的操作,执行完进行内存回收;

可以点击下面的“update”按钮,进行视图的更新;

执行内存回收后,仍然存在于内存中的对象有可能是泄漏的对象;如下图,instance count中红色的部门为不能回收的对象,difference列列出了增加的对象数量和增幅;以String为例,在该操作中增加了31751个对象,增幅达到了14%,随后会在HeapWalker中观察这些对象,分析哪些对象是泄漏的;

一般引起泄漏的对象包括:String,char[],HashMap等,这些对象需要重点关注下;

4. 关闭内存记录:

点击“Stop Recordings”关闭内存记录,告诉jProfiler把这段记录作为分析对象;

5. 找到增加迅速的对象类型,打开HeapWalker:

在视图中找到增长快速的对象类型,一般包括String、char[]、Map等;

在这个操作中,String的增长速度很快。在Liver memory视图中找到String,点右键,选择“Show Selectiion In Heap Walker”,切换到HeapWarker 视图;

切换前会弹出选项页面,注意一定要选择“Select recorded  objects”;这样Heap Walker会在刚刚的那段记录中进行分析;否则,如果不勾选的话,他会分析tomcat的所有内存对象,这样既耗时又不准确;

6. 在HeapWalker中,找到泄漏的对象;

HeapWarker 会分析内存中的所有对象,包括对象的引用、创建、大小和数量;

通过切换到References页签,可以看到具体的对象;

在这些内存对象中,找到泄漏的对象(应该被回收);可以在该对象上点击右键,选择“Use Selected Instances”缩小对象范围;

7. 通过引用分析该对象:

在References引用页签中,可以看到该对象的的引用关系,可以切换incoming/outcoming,显示引用的类型:

incoming  表示显示这个对象被谁引用;

outcoming 表示显示这个对象引用的其他对象;

选择“Show In Graph”将引用关系使用图形方式展现;

选中该对象,点击“Show Paths To GC Root”,会找到引用的根节点;

在上图中,我们可以发现,这个String对象最终的引用是在Thread线程中的ThreadLocalMap对象中;这给我们提供了线索,我们需要在程序中查找有关ThreadLocalMap部分的代码,检查为什么这个对象没有被释放;这往往就是泄漏的根源。

8. 通过创建分析该对象:

如果第7步还不能定位内存泄露的地方,我们可以尝试使用Allocations页签,该页签显示对象是如何创建出来的;
我们可以从创建方法开始检查,检查所有用到该对象的地方,直到找到泄漏位置;

内存泄漏的原因分析:

通过上面的分析,这次内存泄露主要由下面的原因造成:
有操作将对象存放在ThreadLocal的静态变量中,引用不会被释放,所以该对象不会被回收,一直存在于内存中,导致内存泄漏;

参考资料:

1. 转载自: https://blog.csdn.net/coslay/article/details/43270311

2.《利用Java剖析工具JProfiler查找内存泄漏的方法》http://jingyan.baidu.com/article/9c69d48f552d5f13c9024e3b.html

最新文章

  1. (译)你应该知道的jQuery技巧
  2. c#控制IE浏览器自动点击等事件WebBrowser,mshtml.IHTMLDocument2 .
  3. CentOS下安装R
  4. ShellExecute的各种用法
  5. iOS 10 版本适配问题收集-b
  6. GCC编译警告和错误
  7. XST综合、实现过程包含哪些步骤
  8. MinGW安装和使用总结
  9. Codeforces Round #326 (Div. 1) - C. Duff in the Army 树上倍增算法
  10. C#程序调用cmd执行命令-MySql备份还原
  11. Objective-c 数组对象
  12. MVC+ADO模式
  13. bzoj1013 [JSOI2008]球形空间产生器
  14. JS存取Cookies值,附自己写的获取cookies的一个方法
  15. [LeetCode] Complex Number Multiplication 复数相乘
  16. Git源码安装 Linux指定安装目录
  17. django路由系统URLS
  18. centos6.8下LNMP (nginx1.8.0+php5.6.10+mysql5.6.12) - 部署手册
  19. Android SDK 环境变量
  20. 【巷子】---json-server---基本使用

热门文章

  1. Tomcat安装(启动)
  2. 集合框架-LinkedList集合练习(堆栈和队列)
  3. logrotate 日志切割
  4. 带你十天轻松搞定 Go 微服务系列(三)
  5. python函数位置实参传参
  6. 使用 MVVM Toolkit Source Generators
  7. JDBC 连接DRUID 连接池!
  8. CNN-卷积神经网络简单入门(2)
  9. 最近公共祖先-LCA
  10. 简单说说ES6新特性