堆内存行为

时间:2010-10-15 14:52:50

标签: java memory-management

我总是对堆内存行为有疑问。

分析我的应用程序我得到上面的图表。好像很好。但是我不明白为什么,在GC的时候,即使有足够的内存(红色圆圈),堆也会变得很小。

这意味着对于长时间运行的应用程序,它会在一段时间内耗尽堆空间吗?

alt text

2 个答案:

答案 0 :(得分:6)

不一定。垃圾收集器可以以其认为合适的任何方式自由使用最大分配堆。根据当前行为推断未来的GC行为(但具有不同的内存条件)并不能保证准确。

这确实有一个令人遗憾的副作用,即除非确实如此,否则很难确定OutOfMemoryError是否正在进行。一个合法的(但可能非常低效)垃圾收集器可能只是在内存上限被击中之前什么都不做,然后做一个停止世界的标记并扫描整个堆。通过这个实现,你会看到你的记忆不断增加,并且可能会想要说OOME即将来临,但你无法告诉

如此小的堆大小,这里的增加可能仅仅是由于簿记/缓存大小对齐等。你说的是关于规模的分辨率不到50KB,所以我不应该担心。

如果您认为认为存在OutOfMemoryErrors的合法风险,则显示此问题的唯一方法是将压力测试放在一起并显示应用程序确实耗尽了堆空间。

答案 1 :(得分:4)

如果可用空间与总堆大小的比率低于某个阈值,HotSpot垃圾收集器决定在完成GC完成后立即增加总堆大小。可以使用垃圾收集器的许多-XX选项中的一个来调整此比率。

查看内存图,您将看到堆大小增加发生在“锯点”;即局部最大值。其中每个都对应于运行完整的GC。如果仔细查看堆扩展的“点”,您会发现在每种情况下,紧跟在完整GC之后的可用空间量比前一个这样的“点”略高。

我认为正在发生的事情是应用程序的内存使用是周期性的。如果GC在循环的高点或接近高点运行,它将无法释放尽可能多的内存,就好像GC在低点或接近低点运行一样。这种可变性可能足以导致GC扩展堆。

(另一种可能是您的应用程序内存泄漏缓慢。)

  

这意味着对于长时间运行的应用程序,它会在一段时间内耗尽堆空间吗?

没有。假设应用程序的内存使用量(即可达对象占用的空间的积分)是循环的,堆大小将接近固定的上限并且永远不会超过它。当然,OOME并非不可避免。