如何查找Java应用程序中的内存泄漏?

问题描述:

我为生产团队编写了一个应用程序来衡量他们的分数,它运行良好2-3周,然后运行副本的机器减速并重新启动修复它。如何查找Java应用程序中的内存泄漏?

解决此问题的最佳实践步骤是什么?

+0

你是什么意思“的机器......减慢”?你正在重启物理服务器还是java进程? – jtoberon

+0

得到一个调试器/分析器,显示内存使用情况等 –

+2

在这里检查http://olex.openlogic.com/wazi/2009/how-to-fix-memory-leaks-in-java/ –

您需要分析堆并找出哪些对象被保留在那里不应该。

一个选项:

尝试减少-Xmx最大堆大小,以加快内存不足异常,在启动时-XX:+HeapDumpOnOutOfMemoryError将此选项添加到JVM和然后加载生成到像Eclipse Memory Analyzer堆转储。

另一种选择:

使用JMAP从正在运行的进程转储堆(可能需要sudo的权限)

jmap -heap:format=b <pid> 

,并再次,堆转储二进制加载到与jHat或者Eclipse内存分析器。

如果您的应用程序正在减速但未抛出OutOfMemoryError,那么很可能您没有泄漏,但您确实需要做一些JVM tuning,因为它花费了太多的时间来处理GC。

你应该监控GC收集时间(你可以使用-Xloggc:/tmp/gc.out记录它们),也可以使用jstat看到GC的频率发生,并需要多长时间。

如果你有一个拥有大量中等寿命物体的应用程序,是年轻一代足够大(-XX:NewRatio=N)?如果不是你的应用程序将花费很长时间将对象推广到旧版本中,只能在不久之后对其进行GC处理(旧版本的GC相对于新一代而言相对昂贵,尤其是当您的内存已经分散时)。

此外 - 你有没有启用CMS收藏家?如果你有多核机器,我建议你这样做(-XX:+UseConcMarkSweepGC)。

除非使用JNI,否则传统意义上Java中没有内存泄漏。

Java中的内存泄漏通常是指创建您不再使用的引用对象。症状通常是应用程序的内存使用量不断增加。你看到内存使用量增长吗?

如果您在Google中搜索完全相同的问题并按照链接进行操作,那么您最好做好准备。

要解决的最佳实践是通常使用Profiler来检查您的分配。它也可以指向性能瓶颈不是由“内存泄漏”

+1

大量意外的内存使用情况可以发生在保留string.substring(a,b)的返回值时,当字符串最初由大字符数组支持时。 – Joel

+0

这是一个有趣的事实。我不认为我使用子字符串,尽管在这个特定的应用程序中,你的意思是说有其他操作有类似的问题? – davidahines

+0

而且最近的例子是一张地图,你一直在填写密钥,你永远不会再看。例如,在基于Web的应用程序中,如果您将东西存储在具有关键sessionid的地图中,或者甚至更糟糕,则可以使用sessionid +:“+ ,以便您可以在会话期间查看它,然后当会话过期时,那些条目只是坐在那里曾经.. –

您可以检查JVM需要通过使用OS实用内存引起的,如任务管理器或top

您可以使用配置文件来检查您的java代码的内存,例如,Java VisualVM

请记住,Java使用垃圾回收,所以“内存泄漏”的唯一方法是通过持有对(很多)未使用对象的引用。 Josh Bloch's Effective Java项目6(消除陈旧对象引用)解释了这些情况以及如何很好地防止它们。

您还可以使用其他方法来检查这种“内存泄漏”,例如, static analysis and pluggable type systemsjvm memory options

跟踪内存问题的一件好事是通过在启动时向java添加以下命令启用垃圾回收日志记录-verbose:gc-XX:+PrintGCDetails-XX:+PrintGCTimeStamps。然后,您可以分析垃圾回收器的行为方式,即GC运行的频率,垃圾回收器回收内存需要多长时间,回收的内存量以及应用程序的已用内存是否增加。

这里的解释GC日志输出的文档: GC tuning guide for Java 6