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)
Java虚拟机(JVM)以固定的内存上限运行,您可以对其进行修改:
java -Xmx1024m ....
Run Code Online (Sandbox Code Playgroud)
例如,上面的选项(-Xmx ...)将限制设置为1024兆字节.您可以根据需要进行修改(在您的机器,操作系统等的限制范围内).请注意,这与传统应用程序不同,后者将根据需要从操作系统分配越来越多的内存.
但是,更好的解决方案是重新编写应用程序,这样您就不需要一次性将整个文件加载到内存中.这样您就不必调整JVM,也不会占用大量内存.
您无法在内存中读取 10GB 文本文件。你必须先阅读 X MB,用它做一些事情,然后再阅读下一个 X MB。