如果我故意创建了一个在遭受内存泄漏的情况下处理数据的应用程序,我会注意到报告的内存,比如:
Runtime.getRuntime().freeMemory()
开始在1到2 MB的可用内存之间振荡。
然后应用程序进入如下循环:GC,处理一些数据,GC等,但由于GC经常发生,应用程序基本上不再做其他事情了。即使是GUI也需要很长时间才能做出响应(而且,不,我不是在谈论EDT问题,它实际上是VM基本上停留在某种无限的GC模式中)。
我想知道:有没有办法以编程方式检测到JVM没有足够的内存?
请注意,我不是在谈论内存错误,也不是在检测内存泄漏本身。
我在谈论检测到应用程序运行的内存如此之低,以至于它基本上都在调用GC,几乎没有时间做其他事情(在我的假设示例中:处理数据)。
例如,是否可以重复读取在一分钟内可用的内存量,并且看看如果数字在不同值之间“振荡”,例如4 MB,则得出结论:有些泄漏,应用程序已无法使用?答案 0 :(得分:3)
我想知道:有没有办法以编程方式检测到JVM没有足够的内存?
我不这么认为。您可以在任何给定时刻大致了解堆内存的空闲情况,但AFAIK无法可靠地确定何时内存不足。 (当然,你可以做一些事情,比如抓取GC日志文件,或尝试在空闲内存振荡中选择模式。但是面对JVM更改,这些可能是不可靠和脆弱的。)
然而,还有另一种(和IMO更好)的方法。
在Hotspot的最新版本(我相信版本1.6及更高版本)中,您可以调整JVM / GC,以便它能够更快地放弃并抛出OOME。具体来说,可以将JVM配置为检查:
相关的JVM参数是“UseGCOverheadLimit”,“GCTimeLimit”和“GCHeapFreeLimit”。遗憾的是,Hotspot的调整参数在公共网站上没有很好地记录,但是这些参数都列在here中。
假设你希望你的应用程序做一些明智的事情......当它没有足够的内存来运行时就放弃了...然后用比较小的“GCTimeLimitor”或“GCHeapFreeLimit”启动JVM而不是默认值。
修改强>
我发现MemoryPoolMXBean API允许您查看单个内存池(堆)的峰值使用情况,并设置阈值。但是,我从来没有尝试过这个,并且API有很多提示,表明并非所有JVM都实现完整的API。所以,我仍然会推荐HotSpot调优选项方法(见上文)。
答案 1 :(得分:2)
您可以使用getHeapMemoryUsage。
答案 2 :(得分:1)
我看到两个攻击媒介。
监控你的记忆消耗。
当您或多或少经常使用大量可用内存时,很可能是内存泄漏(或者只是使用了太多内存)。 vm将不断尝试释放一些内存而没有太大的成功=>持续的高内存使用率。
您需要将其与经常发生的大型锯齿形图案区分开来,而不是内存问题的指示器。基本上你使用更多的内存,但是当gc找到时间做它的工作时,它会发现很多垃圾,所以一切都很好。
另一个攻击媒介是监视gc运行的频率和成功率。如果它经常在内存中只有很小的增益运行,那么很可能你遇到了问题。
我不知道您是否可以直接从您的程序访问此类信息。但是,如果没有其他我认为你可以在启动时指定参数,这使得gc日志信息成为一个文件,反过来可以解析。
答案 3 :(得分:1)
您可以做的是生成一个定期唤醒的线程,并计算已用内存量并记录结果。然后,您可以对结果执行regression analysis以估计应用程序中的内存增长率。如果您知道增长率和最大内存量,您可以预测(有信心)应用程序何时内存不足。
答案 4 :(得分:0)
您可以将参数传递给java虚拟机,为您提供GC诊断,例如
-verbose:gc
此标志打开GC信息的记录。可得到
在所有JVM中。
- XX:+PrintGCTimeStamps
打印GC发生的时间
相对于开始
应用。
如果您在文件中捕获该输出,则可以在应用程序中定期读取该文件并解析它以了解GC何时发生。因此,您可以计算每个GC之间的平均时间
答案 5 :(得分:0)
我认为JVM会为您完成此操作并抛出java.lang.OutOfMemoryError: GC overhead limit exceeded
。因此,如果你发现OutOfMemoryError并检查该消息,那么你有你想要的,不是吗?
有关详细信息,请参阅this question
答案 6 :(得分:0)
我一直在使用plumbr进行内存泄漏检测,这是一次很棒的体验,虽然许可证非常昂贵:http://plumbr.eu/