我正在将一堆二进制文件(一次一个)读入内存,对它们执行一些操作,然后将它们保存回磁盘。对于小文件,它工作得很好,但是,对于较大的文件,我有相当多的担忧。
现在,假设我正在阅读的文件大小为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 ..我认为不存在“解除分配”内存的方式吗?
我在这里做错了什么?
答案 0 :(得分:3)
简短的回答:Java会在达到它时得到它。 Do not use System.gc();
现在大多数人都有足够的记忆,50mb并不是什么大不了的事。如果您最终必须多次执行此操作,最好的方法是重用大字节数组,这样您才能拥有一个。另一种选择是一次只读取少量文件,进行处理,然后阅读更多文件。但是,无论处理是什么,这都可能不实用。
答案 1 :(得分:2)
如前所述,您不能强制JVM垃圾收集内存,也不能释放内存的某个部分。
然而,您可以更可能释放您的记忆。要了解如何,您必须了解垃圾收集器(GC)的工作原理。简而言之,当它没有被引用到任何地方时它将释放内存。换句话说,当没有对象持有对象A
的引用时,对象A
将有资格进行垃圾回收。有关该主题的简短介绍,请参见the Java tutorial。
因此,您可以通过明确释放对byte[]
的所有引用来增加释放内存的更改。随后对System.gc()
的调用表明,Java虚拟机花费了大量精力来回收未使用的对象,以使其当前占用的内存可用于快速重用“。请注意,这并不能保证它实际上会释放你的记忆!
答案 2 :(得分:0)
Java中的垃圾收集是在JVM认为需要的时候完成的(这是一个非常简单的解释:))。 如果你没有得到错误或异常或类似的东西,你没事。如果您担心应用程序的内存占用,请检查JVM的内存参数: 例如:How can I increase the JVM memory?
答案 3 :(得分:0)
我猜你还有一些对这个方法返回的字节数组的引用。在您没有参考之前,GC不会选择它。您是否可以发布调用此方法的方式以及调用后会发生什么。
答案 4 :(得分:0)
唯一没有被GC自动取消分配的东西是VM外部的资源。
在你的情况下,由于readFileToByteArray
方法总是关闭文件,仍然分配的内存仍然被引用或者还没有垃圾收集
修复它的方法取决于您如何声明需要取消分配的变量。我建议每次读取文件时使用字节数组的新引用,并用尽可能小的范围声明它(如果你有一个for循环内部),那么变量将在年轻代中分配 - 尽快分配。否则在重新影响它之前显式地将引用设置为null。