处理大型Java项目中的内存泄漏的最佳实践?

时间:2010-06-02 18:15:50

标签: java performance tomcat

在我参与的几乎所有大型Java项目中,我都注意到应用程序的服务质量随着容器的正常运行时间而降低。这很可能是由于代码中的内存泄漏造成的。

解决此问题的正确方法显然是追溯问题的根本原因并修复代码中的泄漏。解决问题的快速而简单的方法就是重新启动Tomcat(或者您正在使用的任何servlet容器)。

这是我的三个问题:

  • 假设您选择通过跟踪问题的根本原因(内存泄漏)来解决问题,您将如何收集数据以放大问题?

  • 假设您只需重新启动容器即可选择快速而肮脏的加速方式,您将如何收集数据以选择最佳重启周期?

  • 您是否能够在较长时间内部署和运行项目而无需重新启动servlet容器以重新获得快速恢复?或者偶尔会重新启动一个必须简单接受的servlet?

4 个答案:

答案 0 :(得分:9)

  

假设您选择通过跟踪问题的根本原因(内存泄漏)来解决问题,您将如何收集数据以放大问题?

使用jmap进行堆转储并使用Eclipse Memory Analyzer加载转储。从那里你可以分析哪些物体正在吃掉最多的记忆,哪些“根”阻止其他物体被收集等等。

还有其他堆分析程序,例如jhat,但我发现EMA是最快和最好的(免费)解决方案。

  

假设您通过简单地重新启动容器来选择快速而肮脏的加速方式,您将如何收集数据以选择最佳重启周期?

使用JMX监控堆大小以及其他堆和GC统计信息。

  

您是否能够在很长一段时间内部署和运行项目而无需重新启动servlet容器以重新获得快照?

是。通过避免/修复内存泄漏。

答案 1 :(得分:3)

即使你的代码没有真正的问题,如果你使用的是apache,也会有一些内存泄漏。 查看http://www.tomcatexpert.com/blog/2010/04/06/tomcats-new-memory-leak-prevention-and-detection了解提示和建议

答案 2 :(得分:2)

有一些很棒的分析工具。学会定期使用一个,并了解内存分配输出。

基本上,您可以针对应用的每个重要功能执行此过程:

  • 执行一次
  • 过程
  • GC两次
  • 标记所有对象的当前分配计数
  • 再次浏览您的流程
  • GC两次
  • 再次标记
  • 区分两个标记

如果他们不是非常接近,你可能有泄漏。

如果任何对象计数在此过程的每次迭代中增加给定量,那么您绝对会有泄漏。

答案 3 :(得分:1)

理想情况下,您不需要重新启动程序或servlet。

我的经验是,大多数内存问题的原因通常是由于分配或汇集一小组类中的问题所致。

像VisualVM这样的工具非常适合,因为你可以找出对象分配的主要位置。

对于tomcat来说,这可能有点棘手,因为您也将监视框架,但是经过充分的关注和耐心,您可以经常识别逻辑中的热点。