【问题标题】:OOM while uploading large file上传大文件时OOM
【发布时间】:2019-06-07 12:58:38
【问题描述】:

我需要将一个非常大的文件从我的机器上传到服务器。 (几 GB) 目前,我尝试了以下方法,但我不断得到。

 Caused by: java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Arrays.java:3236)

我可以增加内存,但这不是我想做的事情,因为我不确定我的代码将在哪里运行。我想读取几 MB/kb 并将它们发送到服务器并释放内存并重复。尝试了其他方法,例如 Files utils 或 IOUtils.copyLarge 但我遇到了同样的问题。

URL serverUrl =
                new URL(url);
    HttpURLConnection urlConnection = (HttpURLConnection) serverUrl.openConnection();

    urlConnection.setConnectTimeout(Configs.TIMEOUT);
    urlConnection.setReadTimeout(Configs.TIMEOUT);

    File fileToUpload = new File(file);

    urlConnection.setDoOutput(true);
    urlConnection.setRequestMethod("POST");
    urlConnection.addRequestProperty("Content-Type", "application/octet-stream");

    urlConnection.connect();

    OutputStream output = urlConnection.getOutputStream();
    FileInputStream input = new FileInputStream(fileToUpload);
    upload(input, output);
            //..close streams



private static long upload(InputStream input, OutputStream output) throws IOException {
        try (
                ReadableByteChannel inputChannel = Channels.newChannel(input);
                WritableByteChannel outputChannel = Channels.newChannel(output)
        ) {
            ByteBuffer buffer = ByteBuffer.allocateDirect(10240);
            long size = 0;

            while (inputChannel.read(buffer) != -1) {
                buffer.flip();
                size += outputChannel.write(buffer);
                buffer.clear();
            }

            return size;
        }
    }

我认为这与this 有关,但我不知道我做错了什么。

另一种方法是,但我遇到了同样的问题:

private static long copy(InputStream source, OutputStream sink)
            throws IOException {
        long nread = 0L;
        byte[] buf = new byte[10240];
        int n;
        int i = 0;
        while ((n = source.read(buf)) > 0) {
            sink.write(buf, 0, n);
            nread += n;
            i++;
            if (i % 10 == 0) {
                log.info("flush");
                sink.flush();
            }
        }
        return nread;
    }

【问题讨论】:

  • 我怀疑 URLConnection 正在缓冲内存中的所有内容,以便找出 Content-Length 标头。尝试使用更完整的 HTTP 客户端库。它们很可能具有处理直接发送文件的功能,因此您不必自己进行任何复制。
  • @Thilo 不是 OutputStream 不应该这样做吗?
  • @DenisTulskiy 谢谢;好像是这样的

标签: java arrays file-io out-of-memory


【解决方案1】:

在 Denis Tulskiy 链接到的重复问题上使用 setFixedLengthStreamingModethis answer 一样:

conn.setFixedLengthStreamingMode((int) fileToUpload.length());

来自文档:

当预先知道内容长度时,此方法用于启用 HTTP 请求正文的流式传输,而无需内部缓冲。

目前,您的代码正在尝试将文件缓冲到 Java 的堆内存中,以便计算 HTTP 请求上的 Content-Length 标头。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-06
    相关资源
    最近更新 更多