堆内存行为

6

我一直对堆内存的行为有疑问。

在分析我的应用时,我得到了上面的图表。看起来一切都很好。但是我不明白的是,在GC时,即使有足够的内存(红色圆圈),堆也会稍微增长。

这意味着对于长时间运行的应用程序,它将在某个时候耗尽堆空间吗?

alt text


+1,拥有一个仅需20MB内存的应用程序 ;) - AngerClown
2个回答

6
不一定。垃圾回收器可以自行决定以任何方式使用最大分配的堆内存。基于当前行为(但具有不同的内存条件)来推断未来GC行为并不能保证准确性。
这样做的不幸副作用是,除非出现OutOfMemoryError,否则很难确定它是否会发生。合法(但可能相当低效)的垃圾收集器可以什么也不做,直到达到内存上限,然后对整个堆进行停止-全面标记和扫描。使用此实现,您会看到内存不断增加,并可能认为OOME即将发生,但您无法确定。
对于如此小的堆大小,增加很可能只是由于簿记/缓存大小对齐等原因。从规模的分辨率来看,您所说的不到50KB左右,所以毋需担心。
如果您确实认为存在OutOfMemoryErrors的合法风险,则唯一的方法是组装一个压力测试并显示应用程序确实耗尽了堆空间。

3
除了Andrzej的陈述外,当JVM需要分配更多堆空间时,这可能会对系统造成负担并导致速度变慢。如果您知道应用程序可正常运行的舒适级别,则可以设置一些启动参数以防止该增长。对于原始情况,您似乎在18mb标记处会获得GC。图表显示,您开始分配大约4mb的堆,然后将其提升到20mb左右。只需在程序启动时设置-Xms32mb和-Xmx32mb标志即可。现在,您的JVM无需为您分配更多的堆空间。 - Sean

4
HotSpot垃圾回收器在完成全GC后,如果空闲空间与总堆大小的比例低于某个阈值,将立即决定增加总堆大小。可以使用垃圾回收器的许多-XX选项来调整此比例。 查看内存图表,您会发现堆大小的增加发生在“锯齿点”处; 即局部最大值。每个这样的最大值都对应于运行完全GC。如果您仔细观察堆扩展的“点”,则会发现在每种情况下,紧随完全GC之后的可用空间量比以前的“点”略高。
我想发生的事情是您的应用程序的内存使用是周期性的。如果GC在周期的高点或附近运行,则无法释放与在低点或附近运行时相同的内存。这种变化足以导致GC扩展堆。
(另一个可能性是您的应用程序存在缓慢的内存泄漏。)
这意味着长时间运行的应用程序会在某个时间耗尽堆空间吗?
不会。假设您的应用程序的内存使用情况(即可达对象占用的空间的积分)是循环的,则堆大小将接近固定的高限制,并永远不会超过它。当然,OOME并非不可避免。

只是好奇,你有关于“HotSpot垃圾收集器在完成全GC后立即决定增加总堆大小,如果空闲空间与总堆大小的比率低于某个阈值”的任何来源吗?我想多了解一些。 - matt b
@mattb -- 选项是-XX:MinHeapFreeRatio,如http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html所述。 - Dilum Ranatunga

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接