ApachePOI:垃圾收集不会释放内存[Java]

ApachePOI:垃圾收集不会释放内存[Java],java,excel,memory-leaks,garbage-collection,apache-poi,Java,Excel,Memory Leaks,Garbage Collection,Apache Poi,大家好 我目前正在开发一个工具,该工具使用ApachePOI自动读取excel文件,并根据给定的一组规则重新构造信息。到目前为止,项目进展顺利,但我有一个问题无法解决: -关闭工作簿后,分配给它的内存不会被垃圾回收。 我已经把这个问题分解成一小段代码来复制这个问题。为了可读性,我将省略try/catch块: //the declaration and creation of the objects is seperated due to ommitted try/catch blocks Wor

大家好

我目前正在开发一个工具,该工具使用ApachePOI自动读取excel文件,并根据给定的一组规则重新构造信息。到目前为止,项目进展顺利,但我有一个问题无法解决:

-关闭工作簿后,分配给它的内存不会被垃圾回收。

我已经把这个问题分解成一小段代码来复制这个问题。为了可读性,我将省略try/catch块:

//the declaration and creation of the objects is seperated due to ommitted try/catch blocks
Workbook wb = null;
FileInputStream fs = null;

//opening filestream and workbook
fs = new FileInputStream("C:/Users/XXX/somefile.xlsm");
wb = WorkbookFactory.create(fs);

//closing them again, making them available for garbage collection
fs.close();
wb.close();

//added to make sure that the reference to the workbook/filestream is null
fs = null;
wb = null;

//added to manually trigger gc in hope that this will fix it
Runtime.getRuntime().gc();

//wait forever for me to check the RAM usage
while(true){Thread.sleep(1000)};
一旦使用POI打开工作簿,它似乎就会创建某种缓冲区,以填充Xmx参数指定的最大内存量。关闭工作簿时未释放内存。我还尝试了一个不使用工厂的版本,以检查是否有通过该模块丢失的引用,但没有运气

有人能告诉我为什么内存没有被释放/垃圾回收吗?

顺便说一句,我正在使用ApachePOI3.17,但我也测试了4.0(但不是最近发布的4.0.1,tbh…是的,我是一个黑客和骗子^^)


非常感谢您来自n Runtime.gc()的文档:

运行垃圾收集器。调用此方法表明Java虚拟机花费精力回收未使用的对象,以使它们当前占用的内存可用于快速重用。当控件从方法调用返回时,虚拟机已尽最大努力回收所有丢弃的对象


据我所知,如果JVM不想回收任何东西,即使您调用
Runtime.gc()
,它也不必回收任何东西

你好,

我发现:Java只是懒得减少堆分配。由于该软件只需要在很短的时间内占用大量内存,因此我使用以下JVM参数成功地驯服了这种行为:

-Xms32m
-Xmx1g
-XX:+UnlockExperimentalVMOptions
-XX:+UseG1GC 
-XX:MaxHeapFreeRatio=15 
-XX:MinHeapFreeRatio=5
现在,在操作完成后返回内存

以下是我用来解决这个问题的资源:

  • 以上@Amongalen的评论以及相应的链接:非常感谢
  • 此德国链接介绍堆分配优化技巧:
  • 运行时检查堆内存使用情况的工具
  • 此stackoverflow线程讨论了一个非常类似的问题:。这个线程帮助我正确地塑造JVM参数

感谢所有做出贡献的人。干杯

有趣的是,它使用了多少内存?加载工作簿并关闭它们后,它会增加多少?当你打开并关闭新的工作簿时,它是否一直在增加?最简单的方法是创建一个堆转储并对其进行分析。@标记它使用256mb和-Xmx256,1gb和-Xmx1g等。每当我第一次使用POI时,使用率就会跳到这一点,并一直保持到程序退出为止。这让我觉得我看到的是一个失控的堆缓冲区分配。@Holger感谢您的评论!我将研究堆分析,并检查是否能找到一些东西。问题是内存是否仍在使用。如何检查内存使用情况?请从另一个帖子中查看此答案:感谢您的快速回复,非常感谢!是的,我看到了,但我不想错过它发挥作用的机会。说到问题本身,我发现其他帖子只是告诉OP让变量超出范围或为它们设置null,但显然这也不起作用。