处理大型Java项目中的内存泄漏的最佳实践?
在我参与的几乎所有大型Java项目中,我都注意到应用程序的服务质量随着容器的正常运行时间而降低。 这很可能是由于代码中的内存泄漏造成的。
解决此问题的正确方法显然是追溯问题的根本原因并修复代码中的泄漏。 解决问题的快速而简单的方法就是重新启动Tomcat(或者您正在使用的任何servlet容器)。
这是我的三个问题:
-
假设您选择通过跟踪问题的根本原因(内存泄漏)来解决问题,您将如何收集数据以放大问题?
-
假设您通过简单地重新启动容器来选择快速而肮脏的加速方式,您将如何收集数据以选择最佳重启周期?
-
您是否能够在很长一段时间内部署和运行项目而无需重新启动servlet容器以重新获得快速? 或偶尔的servlet重新启动一个人必须接受的东西?
假设您选择通过跟踪问题的根本原因(内存泄漏)来解决问题,您将如何收集数据以放大问题?
使用jmap
进行堆转储并使用Eclipse Memory Analyzer加载转储。 从那里你可以分析哪些物体正在吃掉最多的记忆,哪些“根”阻止其他物体被收集,等等。
还有其他堆分析程序,例如jhat
,但我发现EMA是最快和最好的(免费)解决方案。
假设您通过简单地重新启动容器来选择快速而肮脏的加速方式,您将如何收集数据以选择最佳重启周期?
使用JMX监视堆大小以及其他堆和GC统计信息。
您是否能够在很长一段时间内部署和运行项目而无需重新启动servlet容器以重新获得快速?
是。 通过避免/修复内存泄漏。
即使你的代码没有真正的问题,如果你使用apache,也可能会有一些内存泄漏。 查看http://www.tomcatexpert.com/blog/2010/04/06/tomcats-new-memory-leak-prevention-and-detection获取提示和建议
那里有一些很棒的分析工具。 学会定期使用一个并了解内存分配输出。
基本上,您可以针对应用的每个重要function执行此过程:
- 完成一次该过程
- GC两次
- 标记所有对象的当前分配计数
- 再次运行您的流程
- GC两次
- 再次标记
- 差分两个标记
如果他们不是非常接近,你可能有泄漏。
如果任何对象计数在此过程的每次迭代中增加给定量,那么您绝对会有泄漏。
理想情况下,您不需要重新启动程序或servlet。
我的经验是,大多数内存问题的原因通常是由于分配或汇集一小组类的问题。
像VisualVM这样的工具非常适合,因为你可以找出对象分配的主要位置。
由于您也将监视框架,因此使用tomcat可能有点棘手,但是通过充分的谨慎和耐心,您可以经常识别逻辑中的热点。