案例——文件句柄(pipe)增多tomcat模块定位方法
问题描述:tomcat文件句柄数持续增长
定位方法:
定位文件句柄泄漏前需要收集的必要信息:
- tomcat初始启动时的文件句柄数、对tomcat的详细lsof结果、以及tomcat的内存dump;
- 按时间段对tomcat的文件句柄数进行统计(每小时、每半天、每天、隔天);
- 若在时间段范围内增长幅度较大(超过100个),则按该时间段连续几次(至少三次)取:tomcat的详细lsof结果、tomcat的内存dump;
- tomcat中运行了哪些模块,以及每个模块的版本;
- 各模块的源码;
7. 根据比较结果中出现差异的对象内存地址(如:0x7c667670)在“incoming reference”列表中找到对应项,逐级展开引用到项目中使用的类所在条目:
8.右键 -> List objects -> with outgoing references
- 使用lsof -p <tomcat-pid>查看具体增多的文件句柄为 pipe/eventpoll(或inode);
- 使用 jmap -dump:format=b,file=xxxx.dmp <tomcat-pid> 多次抓取内存dump(时间间隔依据增长频度来定,增长很快可以隔几分钟抓取,增长较慢可以隔天抓取);
- 使用Eclipse打开这两个内存dump文件;(MAT, Memory Analyzer Tool 插件)
- 在“Histogram”中搜索“sun.nio.ch.EPollSelectorImpl”(Linux平台上的NIO Selector实现类);
- 右键 -> List objects -> with incoming reference
- 分别全选结果(两个内存dump),右键 -> Copy -> Selection,放入文本编辑器中进行比较;
9.逐级展开“classloader”到 WebappClassLoader
10.结果中的 contextName 属性对应的值就是该对象所在 webapps 中的路径。
问题总结:
1、该实例中的文件句柄泄漏为pipe/eventpoll泄漏,这是Java NIO操作未正确关闭Selector所致,文件句柄泄漏发生在Native层面,由于Selector对象已被回收,所以在内存dump中也无法找到对应导致句柄泄漏的Selector对象;
2、注:这种方式找到的只是发生重新创建NIO连接的web模块,这并不一定意味着就是发生文件句柄泄漏的模块;但是,发生文件句柄泄漏就一定意味着有对象重新创建/新创建;所以,这个定位结果对终止问题定位具有较大的参考意义。