Java 如何在将大型二进制文件读入内存后进行清理

Java 如何在将大型二进制文件读入内存后进行清理,java,memory-management,memory-leaks,Java,Memory Management,Memory Leaks,我将一堆二进制文件(一次一个)读入内存,对它们执行一些操作,然后将它们保存回磁盘。对于小文件,它工作得非常好,但是对于大文件,我有相当多的担心 现在,假设我正在读取的文件是25Mb大——这就是我的代码的样子:- public static byte[] returnEncryptedFileData(File fileObj) { byte[] fileData = FileUtils.readFileToByteArray(fileObj); //now performing some ope

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

现在,假设我正在读取的文件是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。。我认为不存在“释放”内存的方法


我做错了什么?

简单的回答是:Java会在它到达时到达它


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

简单的回答是:Java将在它到达时到达它


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

只要JVM认为需要,Java中的垃圾收集就会完成(这是一个非常简单的解释:)。 如果你没有遇到错误、异常或类似的情况,你就没事了。如果您担心应用程序的内存占用,请检查JVM的内存参数:
e、 g.:

只要JVM认为需要,Java中的垃圾收集就会完成(这是一个非常简单的解释:)。 如果你没有遇到错误、异常或类似的情况,你就没事了。如果您担心应用程序的内存占用,请检查JVM的内存参数:
e、 g.:

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

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

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

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


因此,您可以通过显式释放对
字节[]
的所有引用来增加内存释放量。对
System.gc()
“的后续调用表明Java虚拟机花费精力回收未使用的对象,以便使它们当前占用的内存可用于快速重用”。请注意,这并不能保证它会真正释放您的内存

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

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


因此,您可以通过显式释放对
字节[]
的所有引用来增加内存释放量。对
System.gc()
“的后续调用表明Java虚拟机花费精力回收未使用的对象,以便使它们当前占用的内存可用于快速重用”。请注意,这并不能保证它会真正释放您的内存

GC不会自动取消分配的只有VM外部的资源。
在您的情况下,
readFileToByteArray
方法总是关闭文件,仍然分配的内存仍然被引用或尚未被垃圾回收


解决方法取决于如何声明需要取消分配的变量。我建议每次读取文件时使用字节数组的新引用,并用尽可能小的作用域(如果有for循环,则在for循环内部)声明它,以便在年轻一代中分配变量,并尽快取消分配。否则,请在重新影响其前将引用显式设置为null。

GC不会自动取消分配的唯一内容是VM外部的资源。
在您的情况下,作为
readFileToByteArray
方法,始终关闭该文件