调用垃圾回收会导致程序在java中使用更少的堆内存
Posted
技术标签:
【中文标题】调用垃圾回收会导致程序在java中使用更少的堆内存【英文标题】:Calling garbage collection causes the program to use less heap memory in java 【发布时间】:2013-01-02 07:20:52 【问题描述】:这与我的问题Java Excel POI stops after multiple execution by quartz有关。
我的程序在几次迭代后意外停止。我尝试进行分析,发现每次迭代都消耗了大量的堆内存(并且某个地方的内存泄漏……还没有找到问题所在)。因此,作为临时解决方案,我尝试在程序的每次完整执行结束时插入System.gc();
(请阅读链接的问题以获取程序的简要说明)。我并没有期待太多,每次迭代后可能会有更多可用的堆空间。但是,当我插入System.gc();
时,程序使用的堆内存似乎更少。
上图显示了使用System.gc();
运行的程序,而下图是没有运行的程序。如您所见,上图显示在程序的 4 次迭代后我只使用了不到 100mb 的空间,而下图显示在相同数量的迭代中使用超过 100mb。谁能澄清System.gc();
在我的堆中如何以及为什么会导致这种影响?如果我在我的程序中使用它有什么缺点吗?还是我编程完全没希望转而摄影?
请注意,我在每次程序迭代结束时插入了 GC。所以我假设在满足System.gc();
命令之前,堆的使用必须和没有插入GC的情况一样
谢谢!
【问题讨论】:
【参考方案1】:谁能澄清 System.gc() 的方式和原因;在我的堆中造成这种影响?
System.gc
是一种让垃圾收集器运行的请求服务。请注意,我在声明中使用了request
而不是trigger
。基于堆状态的 GC 可能/不进行收集。
如果我在我的程序中使用它有什么缺点吗?
根据经验,GC 在单独使用时效果最好。在您的示例中,您不必担心或使用System.gc
。因为 GC 将在最佳运行时运行,手动请求它可能会降低性能。尽管只有很小的差异,但您可以观察到下图中的“花费在 gc 上的时间”比第一个要好。
根据记忆,两个图表都可以。好像你的最大堆有点高。因此 GC 没有在第二张图中运行它。如果真的需要,它会运行它。
【讨论】:
@ides 为了补充 Jatin 的答案,您必须记住,已使用的堆包括可以收集的垃圾。只要你低于触发 GC 的级别(这取决于所使用的算法),堆就会不断增长,这是正常的:垃圾收集本身是有代价的,所以你必须在频率之间找到一个平衡点以及它引入的延迟。管理它的第一步是简单地调整Xmx
。【参考方案2】:
根据 Java 规范,调用 gc() 并不能保证它会运行,您只是向 JVM 提示您需要它运行,因此结果不可靠(无论如何都应该避免调用 gc()什么)。但是,在您的情况下,由于堆逐渐达到临界限制,这就是为什么您的提示正在被执行的原因。
GC 通常基于特定算法运行以防止堆被耗尽,当它无法回收急需的空间而没有更多堆供您的应用生存时,您将面临OutOfMemoryException
。
当 GC 运行时,您的应用程序会因为它的活动而经历一些暂停,所以您不会真的希望它运行得更频繁!
最好的办法是解决泄漏问题并练习更好的内存管理以获得健康的运行时体验。
【讨论】:
【参考方案3】:使用 System.gc() 不应影响分配给 JVM 的堆大小。堆大小仅取决于我们提供给 JVM 的启动参数。我会建议你运行相同的程序 3-4 次,并在使用 System.gc() 和不使用 System.gc() 的情况下取平均值。
回到寻找内存泄漏的问题;我会推荐使用 JProfiler 或其他工具来告诉你确切的内存占用;以及堆中的不同对象。
最后但并非最不重要的;你是一个合理的程序员。不需要去拍照:)
【讨论】:
这是不正确的。有几个 JVM 参数可以让您控制堆大小。您可以控制初始堆的大小以及堆的最大大小。默认情况下,Java 不会在启动时分配完整的堆空间,但会在需要时扩大堆。当垃圾收集器能够释放内存时,显然没有内存泄漏...... @MathiasSchwarz 我同意你的说法。甚至我提到堆大小仅取决于我们可以指定最小和最大堆大小的 JVM 参数。 感谢您的回复。我确实对该程序进行了几次分析,结果与我上面提到的非常相似。至于堆大小,我将其设置为 512m。区别在于使用的堆而不是初始堆和最大堆。我目前正在尝试查找内存泄漏,但我很难找到它。就像雪地里的头皮屑。以上是关于调用垃圾回收会导致程序在java中使用更少的堆内存的主要内容,如果未能解决你的问题,请参考以下文章