减少Java堆大小

3

我有一个应用程序,需要比较两个可能非常大(100k+)的目录内容,这会使用大量内存,但我认为这是有道理的。但是,一旦我的比较操作完成后,堆大小仍然保持不变。

基本上,我的代码实例化了一个类,用于保存源和目标文件的文件名、文件大小、路径和修改日期。我把新增、删除和更新保存在其他数组中。然后,我使用clear()清除源和目标数组(现在可能每个数组都有100k+),只剩下相对较小的新增、删除和更新数组。

然而,在我清除目标和源数组之后,内存使用量(通过VirtualVM和Windows任务管理器可见)并没有下降。我没有足够的经验来使用VirtualVM(或任何分析工具)来确定占用所有这些内存的原因。VirtualVM的堆转储列出了几个保留大小为几兆字节的顶级对象。

请问有什么方法可以帮助指导我正确地解决问题吗?


1
你确定当你查看内存使用情况时垃圾回收器已经运行了吗?只有在运行一次(可能是主要的)GC之后,内存使用情况才会下降。 - cello
根据VirtualVM的数据,堆大小基本保持不变,而已使用的堆会下降(降至我预期的水平,远低于总堆大小的一半)。堆大小大致与Windows任务管理器显示的Java使用量相符。在分析应用程序时,我看到了通常的GC阶梯式收集模式,只是不知道为什么总堆大小仍然如此之大。 - tau
3个回答

2
如果垃圾回收后使用的堆下降,那么它很可能按预期工作。Java在需要更多内存时增加其堆,但不释放它--它更喜欢保留它,以防应用程序再次使用更多内存。有关为什么在使用的堆量减少后堆不会减小的主题,请参见是否有一种方法可以在不使用时降低Java堆?。请注意保留HTML标记。

我刚才浏览了一下那个帖子,已经非常有启发性了。谢谢! - tau

2
虚拟机会根据命令行参数-XX:MinHeapFreeRatio-XX:MaxHeapFreeRatio来增加或缩小堆。当空闲百分比达到-XX:MaxHeapFreeRatio时,虚拟机将缩小堆,其默认值为70。在Oracle的错误#6498735中简要讨论了这个问题。

1
根据您的代码,可能会产生内存泄漏,垃圾收集器无法释放它们。建议您检测潜在的内存泄漏并进行修复。然后再看看代码本身是否可以改进。注意,例如如果使用try/catch/finally块,则finally块可能根本不被调用(或者至少不是立即)。如果在finally块中进行一些资源释放,则这可能是答案。请阅读相关主题,例如在此处:http://www.toptal.com/java/hunting-memory-leaks-in-java

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