Java 以编程方式检测内存泄漏

Java 以编程方式检测内存泄漏,java,memory-leaks,Java,Memory Leaks,如果我故意创建了一个应用程序,在内存泄漏的情况下处理数据,我可以注意到,报告的内存如下: Runtime.getRuntime().freeMemory() 开始在1到2 MB的可用内存之间振荡 然后,应用程序进入如下循环:GC,处理一些数据,GC,等等。但是由于GC经常发生,应用程序基本上不再做其他事情。甚至GUI也需要很长时间才能做出响应(不,我这里不是说EDT问题,实际上是虚拟机基本上陷入了无休止的GC’ing模式) 我想知道:有没有一种方法可以通过编程检测JVM没有足够的内存 请注意,

如果我故意创建了一个应用程序,在内存泄漏的情况下处理数据,我可以注意到,报告的内存如下:

Runtime.getRuntime().freeMemory()
开始在1到2 MB的可用内存之间振荡

然后,应用程序进入如下循环:GC,处理一些数据,GC,等等。但是由于GC经常发生,应用程序基本上不再做其他事情。甚至GUI也需要很长时间才能做出响应(不,我这里不是说EDT问题,实际上是虚拟机基本上陷入了无休止的GC’ing模式)

我想知道:有没有一种方法可以通过编程检测JVM没有足够的内存

请注意,我不是在谈论内存错误的ouf,也不是在谈论检测内存泄漏本身

我说的是检测一个应用程序的内存太少,以至于它基本上一直在调用GC,几乎没有时间做其他事情(在我假设的示例中:处理数据)


例如,重复读取(比如)一分钟内的可用内存量,并查看该数字是否在不同值之间“振荡”,所有值均低于(比如)4MB,断定出现了一些漏洞,并且应用程序变得不可用?

您可以将参数传递给java虚拟机,该虚拟机为您提供GC诊断,例如

  • -verbose:gc
    此标志打开gc信息的日志记录。可用 在所有JVM中

  • -
    XX:+PrintGCTimeStamps
    打印GCs发生的时间 相对于开始的 应用程序

  • 如果将该输出捕获到文件中,则在应用程序中可以周期性地读取该文件并对其进行解析,以了解GC何时发生。因此,您可以计算出每次GC之间的平均时间

    我想知道:有没有一种方法可以通过编程检测JVM没有足够的内存

    我不这么认为。您可以大致了解在任何给定时刻有多少堆内存可用,但是您无法可靠地确定何时内存不足。(当然,你可以做一些事情,比如抓取GC日志文件,或者尝试在空闲内存振荡中选择模式。但是,面对JVM的变化,这些可能是不可靠和脆弱的。)

    然而,还有另一种(也是海事组织更好的)方法

    在Hotspot的最新版本(我相信是1.6版和更高版本)中,可以调优JVM/GC,使其放弃并更快抛出OOME。具体而言,可以将JVM配置为检查:

    • 完全GC后,空闲堆与总堆的比率大于给定阈值,和/或
    • 运行GC所花费的时间少于总时间的某个百分比
    相关的JVM参数是“UseGCOverdeLimit”、“GCTimeLimit”和“GCHeapFreeLimit”。不幸的是,Hotspot的调优参数在公共web上没有很好的文档记录,但这些参数都列出了

    假设您希望应用程序执行合理的操作。。。当它没有足够的内存正常运行时放弃。。。然后只需使用比默认值更小的“GCTimeLimitor”或“GCHeapFreeLimit”启动JVM

    编辑


    我发现允许您查看单个内存池(堆)的峰值使用情况,并设置阈值。然而,我从未尝试过这种方法,API中有很多提示表明并非所有JVM都实现完整的API。因此,我仍然推荐热点调优选项方法(见上文)而不是此方法。

    我看到了两种攻击向量

    要么监视内存消耗

    当您或多或少地经常使用大量可用内存时,很可能是内存泄漏(或者只是使用了太多内存)。虚拟机将不断尝试释放一些内存,但没有多大成功=>持续的高内存使用率

    您需要将其与经常发生的大型之字形模式区分开来,而这并不是内存问题的指标。基本上,你会使用更多的内存,但是当gc找到时间做它的工作时,它会发现很多垃圾要带出来,所以一切都很好

    另一个攻击向量是监视GC运行的频率和成功的种类。如果它经常运行,但内存增益很小,那么很可能您遇到了问题


    我不知道你是否可以直接从你的程序中获取这类信息。但是,如果没有其他方法,我认为您可以在启动时指定参数,使gc日志信息变成一个文件,然后可以对其进行解析。

    您可以使用。

    您可以做的是生成一个线程,该线程会定期唤醒,并计算使用的内存量并记录结果。然后,您可以根据结果来估计应用程序中的内存增长率。如果您知道增长率和最大内存量,您可以(有信心地)预测应用程序何时会耗尽内存。

    我认为JVM正是为您这样做的,并抛出
    java.lang.OutOfMemoryError:GC开销限制超过了
    。所以,若你们发现了OutOfMemoryError并检查了那个条消息,那个么你们就得到了你们想要的,不是吗


    有关更多详细信息,请参阅。

    我一直在使用Plumber进行内存泄漏检测,这是一次很棒的体验,尽管许可证非常昂贵:

    我认为更好的办法是修复您的代码。@San Jacinto:您的评论目光短浅,很有吸引力,但这与此无关。如果你有什么有价值的东西要提供,你可能想重新阅读问题和答案。只有当你的代码出了问题时。并不是所有的第三方软件都是平等的,也不是一劳永逸的。我以为你可以插入一个GC钩子。。。让我想想……@马克·斯托尔:没错。。。而且,如果对我来说,这只是一个有趣的理论问题。