1

我正在将一堆二进制文件(一次一个)读入内存以对它们执行一些操作,然后将它们保存回磁盘。对于小文件,它工作得非常好,但是,对于较大的文件,我有很多担忧。

现在,假设我正在阅读的文件是 25Mb 大 - 这就是我的代码的样子: -

public static byte[] returnEncryptedFileData(File fileObj) {
byte[] fileData = FileUtils.readFileToByteArray(fileObj);
//now performing some operations on fileData

return fileData;
    }

在这段代码执行之后,我看到 (50Mb + MISC) 的额外空间消耗(这很好,因为会有 2 个字节数组 - 一个是我定义的 fileData,另一个是 readFileToByteArray 用来执行操作的,每个都持有25Mb 的数据)

但是,即使在此方法返回并再次调用下一个要读取的文件后,之前持有的内存也不会释放!如果正在读取的下一个文件是 30Mb 大,我会看到 (50Mb + 60Mb + MISC) 的内存消耗

如何在将文件读取到字节数组后进行清理,对其执行一些操作,然后从方法中返回它。System.gc() 没有帮助,因为它不会立即执行 GC.. 我认为不可能“释放”内存?

我在这里做错了什么?

4

5 回答 5

3

简短的回答:Java 会在它得到它时得到它。不要使用_System.gc();

现在大多数人都有足够的内存,50mb 并不是什么大问题。如果您最终不得不多次执行此操作,最好的办法是重用您的大字节数组,这样您就只有一个。另一种选择是一次只读取少量文件,进行处理,然后阅读更多。但是,无论处理是什么,这可能都不实用。

于 2013-04-08T11:51:17.360 回答
2

如前所述,您不能强制 JVM 对您的内存进行垃圾收集,或释放某部分内存。

但是,您可以使您的内存更有可能被释放。要了解其原理,您必须了解垃圾收集器 (GC) 的工作原理。简而言之,当它没有被任何地方引用时,它将释放内存。换句话说,当没有对象持有对 object 的引用时A, objectA将有资格进行垃圾回收。有关该主题的简短介绍,请参阅Java 教程

因此,您可以通过显式释放对byte[]. 随后调用System.gc()“建议 Java 虚拟机花费精力回收未使用的对象,以使它们当前占用的内存可用于快速重用”。请注意,这并不能保证它实际上会释放您的内存!

于 2013-04-08T11:59:26.243 回答
0

每当 JVM 认为需要时,Java 中的垃圾收集就会完成(这是一个非常简单的解释 :))。如果您没有收到错误或异常或类似的信息,那您很好。如果您担心应用程序的内存占用,请检查 JVM 的内存参数:例如:如何增加 JVM 内存?

于 2013-04-08T11:52:50.010 回答
0

我猜您仍然对此方法返回的字节数组有一些参考。除非您没有参考它,否则 GC 不会选择它。您能否也发布调用此方法的方式以及调用后会发生什么。

于 2013-04-08T11:55:39.857 回答
0

唯一不会被 GC 自动取消分配的是 VM 外部的资源。
在您的情况下,由于该readFileToByteArray方法始终关闭文件,因此仍分配的内存仍被引用或尚未被垃圾回收

修复它的方法取决于您如何声明需要取消分配的变量。我建议每次读取文件时都使用字节数组的新引用,并以尽可能小的范围声明它(如果有,则在 for 循环内),以便在年轻一代中分配变量-尽快分配。否则,在重新影响它之前明确地将您的引用设置为 null。

于 2013-04-08T12:01:18.820 回答