执行“时发生OutOfMemoryError错误”;“文件到字节[]”;在Java中使用大型文件?

执行“时发生OutOfMemoryError错误”;“文件到字节[]”;在Java中使用大型文件?,java,file,bytearray,heap,space,Java,File,Bytearray,Heap,Space,我尝试了各种代码将大型CSV文件(~300 MB)转换为字节[],但每次都失败,导致Java堆空间错误,如下所示: 184898[jobLauncherTaskExecutor-1]调试 org.springframework.batch.core.step.tasklet.TaskletStep-回滚 对于错误:java.lang.OutOfMemoryError:java堆空间185000 [jobLauncherTaskExecutor-1]调试 org.springframework.t

我尝试了各种代码将大型CSV文件(~300 MB)转换为字节[],但每次都失败,导致Java堆空间错误,如下所示:

184898[jobLauncherTaskExecutor-1]调试 org.springframework.batch.core.step.tasklet.TaskletStep-回滚 对于错误:java.lang.OutOfMemoryError:java堆空间185000 [jobLauncherTaskExecutor-1]调试 org.springframework.transaction.support.TransactionTemplate- 启动应用程序异常时的事务回滚 java.lang.OutOfMemoryError:java堆空间 位于java.util.Arrays.copyOf(Arrays.java:2367) 位于java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:130) 位于java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:114) 位于java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:415) 位于java.lang.StringBuffer.append(StringBuffer.java:237) 位于org.apache.log4j.helpers.PatternParser$LiteralPatternConverter.format(PatternParser.java:419) 位于org.apache.log4j.PatternLayout.format(PatternLayout.java:506) 位于org.apache.log4j.WriterAppender.subAppend(WriterAppender.java:310) 位于org.apache.log4j.WriterAppender.append(WriterAppender.java:162) 位于org.apache.log4j.AppenderSkeleton.doAppend(AppenderSkeleton.java:251) 位于org.apache.log4j.helpers.appenderatachableimpl.appenderlooponappenders(appenderatachableimpl.java:66) 位于org.apache.log4j.Category.callAppenders(Category.java:206) 位于org.apache.log4j.Category.forcedLog(Category.java:391) 位于org.apache.log4j.Category.log(Category.java:856) 位于org.slf4j.impl.Log4jLoggerAdapter.log(Log4jLoggerAdapter.java:601) 位于org.apache.commons.logging.impl.SLF4JLocationAwareLog.debug(SLF4JLocationAwareLog.java:133) 位于org.apache.http.impl.conn.Wire.Wire(Wire.java:77) 位于org.apache.http.impl.conn.Wire.output(Wire.java:107) 位于org.apache.http.impl.conn.LoggingSessionOutputBuffer.write(LoggingSessionOutputBuffer.java:76) 位于org.apache.http.impl.io.ContentLengthOutputStream.write(ContentLengthOutputStream.java:119) 位于org.apache.http.entity.ByteArrayEntity.writeTo(ByteArrayEntity.java:115) 位于org.apache.http.entity.HttpEntityWrapper.writeTo(HttpEntityWrapper.java:98) 位于org.apache.http.impl.client.EntityEnclosingRequestWrapper$EntityWrapper.writeTo(EntityEnclosingRequestWrapper.java:108) 位于org.apache.http.impl.entity.EntitySerializer.serialize(EntitySerializer.java:122) 位于org.apache.http.impl.AbstractHttpClientConnection.sendRequestEntity(AbstractHttpClientConnection.java:271) 位于org.apache.http.impl.conn.AbstractClientConnAdapter.sendRequestEntity(AbstractClientConnAdapter.java:227) 位于org.apache.http.protocol.HttpRequestExecutor.doSendRequest(HttpRequestExecutor.java:257) 位于org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:125) 位于org.apache.http.impl.client.DefaultRequestDirector.tryExecute(DefaultRequestDirector.java:712) 位于org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:517) 位于org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906) 位于org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:805)

到目前为止,我已尝试使用以下版本的代码将文件转换为
byte[]

版本1:核心Java

    File file = new File(fileName);
    FileInputStream fin = null;
    byte fileContent[] = null;

    try {
        fin = new FileInputStream(file);

        fileContent = new byte[(int) file.length()];

        fin.read(fileContent);

    } catch (FileNotFoundException e) {
        System.out.println("File not found" + e);
    } catch (IOException ioe) {
        System.out.println("Exception while reading file " + ioe);
    } finally {
        try {
            if (fin != null) {
                fin.close();
            }
        } catch (IOException ioe) {
            System.out.println("Error while closing stream: " + ioe);
        }
    }

    return fileContent;
版本2:Java7NIO

    Path path = Paths.get(fileName);

    byte[] data = null;

    try {
        data = Files.readAllBytes(path);
    } catch (IOException e) {
        e.printStackTrace();
    }

    return data;
版本3:ApacheCommonsIO

    File file = new File(fileName);
    FileInputStream fis = null;
    byte fileContent[] = null;

    try {
        fis = new FileInputStream(file);

        fileContent = IOUtils.toByteArray(fis);

    } catch (FileNotFoundException e) {
        System.out.println("File not found" + e);
    } catch (IOException ioe) {
        System.out.println("Exception while reading file " + ioe);
    } finally {
        try {
            if (fis != null) {
                fis.close();
            }
        } catch (IOException ioe) {
            System.out.println("Error while closing stream: " + ioe);
        }
    }

    return fileContent;
版本4:谷歌番石榴

    File file = new File(fileName);
    FileInputStream fis = null;
    byte fileContent[] = null;

    try {
        fis = new FileInputStream(file);

        fileContent = ByteStreams.toByteArray(fis);

    } catch (FileNotFoundException e) {
        System.out.println("File not found" + e);
    } catch (IOException ioe) {
        System.out.println("Exception while reading file " + ioe);
    } finally {
        try {
            if (fis != null) {
                fis.close();
            }
        } catch (IOException ioe) {
            System.out.println("Error while closing stream: " + ioe);
        }
    }

    return fileContent;
版本5:Apache.commons.io.FileUtils

File file = new File(fileName);

byte fileContent[] = null;

try {

    fileContent =  org.apache.commons.io.FileUtils.readFileToByteArray(file);

} catch (FileNotFoundException e) {
    System.out.println("File not found" + e);
} catch (IOException ioe) {
    System.out.println("Exception while reading file " + ioe);
}

return fileContent;
我甚至将堆空间设置为相当大。对于我的外部Tomcat,它大约是6GB(5617772K),如任务管理器中的内存消耗所示

对于前三个版本的代码,在命中此byte[]生成代码时,堆空间突然增加到5 GB以上,然后失败。Google Guava似乎很有希望,在命中byte[]生成代码后,内存消耗保持在3.5 GB左右相当长的一段时间,大约10分钟,然后突然跳到5 GB以上,失败了


我想不出解决这个问题的办法。有人能帮我解决这个问题吗?在此方面的任何帮助都将不胜感激。

一个300MB的文件在加载到字节数组时不会消耗6GB的堆。再仔细看一下你的stacktrace,似乎装载部分完全没有问题。“java.lang.OutOfMemoryError:java堆空间”仅在尝试使用Log4j记录某些内容时才会抛出


日志记录似乎源于第三方代码,而不是您自己的代码,因此您可能无法更改正在记录的内容,但您肯定可以通过Log4j配置减少日志记录,尝试增加org.apache的日志级别(警告、错误或致命)。*您应该准备好了。

如何解决?不要一次读取整个文件。但请注意,在读取文件时没有出现上述故障。更确切地说,您耗尽了存储日志记录,可能是因为您试图一次记录整个文件。无论您如何读取它,如果文件太大,它将无法装入内存。你不需要这样做。文件可以一次处理一条记录。不管你的堆有多大,总有一个文件比这个大。逐行读取csv文件。有很多类,至少@MSR:发送请求的方式实际上也与这个问题相关。它是否是对ApacheHttpClient API的直接调用?它是通过一个框架完成的吗。。。因为,当然,关闭日志记录会有所帮助(配置Log4J以禁用
org.apache.http.wire
的调试日志记录以实现这一点),但您真正应该做的是