Java OutOfMemoryError在读取大文本文件时

A.P*_*P.S 17 java arrays file-io bytearray out-of-memory

我是Java的新手,正在阅读非常大的文件,需要一些帮助来理解问题并解决它.我们有一些遗留代码必须进行优化才能使其正常运行.文件大小只能从10mb到10gb不等.只有文件启动超过800mb大小时才会启动麻烦.

InputStream inFileReader = channelSFtp.get(path); // file reading from ssh.
byte[] localbuffer = new byte[2048];
ByteArrayOutputStream bArrStream = new ByteArrayOutputStream();

int i = 0;
while (-1 != (i = inFileReader.read(buffer))) {
bArrStream.write(localbuffer, 0, i);
}

byte[] data = bArrStream.toByteArray();
inFileReader.close();
bos.close();
Run Code Online (Sandbox Code Playgroud)

我们收到了错误

java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Arrays.java:2271)
    at java.io.ByteArrayOutputStream.grow(ByteArrayOutputStream.java:113)
    at java.io.ByteArrayOutputStream.ensureCapacity(ByteArrayOutputStream.java:93)
    at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:140)
Run Code Online (Sandbox Code Playgroud)

任何帮助,将不胜感激?

Tak*_*aki 19

尝试使用java.nio.MappedByteBuffer.

http://docs.oracle.com/javase/7/docs/api/java/nio/MappedByteBuffer.html

您可以将文件的内容映射到内存而无需手动复制.高级操作系统提供内存映射,Java具有API以利用该功能.

如果我的理解是正确的,内存映射不会将文件的整个内容加载到内存中(意思是"根据需要部分加载和卸载"),所以我猜一个10GB的文件不会占用你的内存.


tte*_*kin 13

即使你可以增加JVM内存限制,它也是不必要的,并且分配一个像10GB这样的巨大内存来处理文件听起来过度和资源密集.

目前,您正在使用"ByteArrayOutputStream"来保留内部存储器以保留数据.代码中的这一行会将最后读取的2KB文件块附加到此缓冲区的末尾:

bArrStream.write(localbuffer, 0, i);
Run Code Online (Sandbox Code Playgroud)

bArrStream不断增长,最终耗尽内存.

相反,您应该重新组织算法并以流方式处理文件:

InputStream inFileReader = channelSFtp.get(path); // file reading from ssh.
byte[] localbuffer = new byte[2048];

int i = 0;
while (-1 != (i = inFileReader.read(buffer))) {
    //Deal with the current read 2KB file chunk here
}

inFileReader.close();
Run Code Online (Sandbox Code Playgroud)


Bri*_*new 7

Java虚拟机(JVM)以固定的内存上限运行,您可以对其进行修改:

java -Xmx1024m ....
Run Code Online (Sandbox Code Playgroud)

例如,上面的选项(-Xmx ...)将限制设置为1024兆字节.您可以根据需要进行修改(在您的机器,操作系统等的限制范围内).请注意,这与传统应用程序不同,后者将根据需要从操作系统分配越来越多的内存.

但是,更好的解决方案是重新编写应用程序,这样您就不需要一次性将整个文件加载到内存中.这样您就不必调整JVM,也不会占用大量内存.


sig*_*igi 5

您无法在内存中读取 10GB 文本文件。你必须先阅读 X MB,用它做一些事情,然后再阅读下一个 X MB。

  • 如果他有 10Gb 和 64 位 JVM,他*可以*做到这一点。不过,他可能不应该。 (3认同)

Sam*_*ane 5

使用命令行选项-Xmx运行Java,该选项设置堆的最大大小.

详情请见此处..