OOM при загрузке большого файла - PullRequest
0 голосов
/ 07 июня 2019

Мне нужно загрузить очень большой файл со своего компьютера на сервер.(несколько ГБ) В настоящее время я попробовал следующий подход, но продолжаю получать.

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

Я могу увеличить память, но это не то, что я хочу сделать, потому что не уверен, где будет выполняться мой код.Я хочу прочитать несколько МБ / КБ, отправить их на сервер, освободить память и повторить.пробовал другие подходы, такие как 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;
        }
    }

Я думаю, что это как-то связано с этим , но я не могу понять, что я делаю неправильно.

Другой подход был, но я получилта же проблема:

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;
    }

1 Ответ

1 голос
/ 10 июня 2019

Использовать setFixedLengthStreamingMode согласно этому ответу на дубликат вопроса Денис Тульский связан с:

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

Из документов:

Этот метод используется для включения потоковой передачи тела HTTP-запроса без внутренней буферизации, когда длина содержимого заранее известна.

В данный момент ваш код пытается буферизовать файл в Java.память кучи для вычисления заголовка Content-Length в HTTP-запросе.

...