Я получаю OutOfMemoryError из java.lang.StringBuilder.append, даже когда я устанавливаю размер памяти на 32 ГБ и считываю в построитель только файл размером 500 МБ.
java.lang.OutOfMemoryError: null
at java.base/java.lang.AbstractStringBuilder.hugeCapacity(AbstractStringBuilder.java:214) ~[na:na]
at java.base/java.lang.AbstractStringBuilder.newCapacity(AbstractStringBuilder.java:206) ~[na:na]
at java.base/java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:173) ~[na:na]
at java.base/java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:538) ~[na:na]
at java.base/java.lang.StringBuilder.append(StringBuilder.java:174) ~[na:na]
at com.github.loa.indexer.service.index.base64.Base64Encoder.encode(Base64Encoder.java:31) ~[classes/:na]
Мой вариант использования довольно сложный. Пытаясь передать файл в массивы байтов в кусках длиной 3072 байта, затем закодировать куски с помощью java.util.Base64, добавить результат кодирования в StringBuilder. К сожалению, StringBuilder быстро умирает. Мне нужно получить всю строку base64 в памяти, чтобы отправить ее в Elasticsearch (потоковая передача невозможна). Код доступен здесь: github.com/bottomless-archive-project/library-of-alexandria/…
Какую версию Java вы используете?
@Andreas Java 11. Я думаю, что это относится к Java 9+, но не уверен.
Немного небрежно, что они бросают OOM. Теперь мне нужно поймать это где-то в моем коде, и я знаю, что ловить OOM довольно плохо.
Это происходит потому, что массив байтов, который StringBuilder хочет выделить, потребует большего размера массива, чем разрешено JVM (более 2147483647 элементов, также известных как Integer.MAX_VALUE).
Иными словами, это ограничение Java, что размер строки не может превышать 2 ГБ, что обычно означает, что он не может превышать 1 миллиард символов (строки только для latin1 могут иметь 2 миллиарда символов в более поздних версиях Java).
Было бы здорово добавить фрагмент кода, чтобы получить больше информации о том, что происходит.