ThreadLocal <ByteArrayOutputStream>вызывает OutOfMemory - PullRequest
0 голосов
/ 11 сентября 2018

Когда мой класс структурирован таким образом, я получаю ошибку OutOfMemory.

DataHandler вызывается фиксированным пулом из 8 потоков (управление внешним пулом потоков отсутствует. Создан фиксированный пулодин раз, выполняется один раз, и если поток умирает, новый поток не создается).В то же время несколько потоков вызывают DataHandler, но поскольку byteArrayOutputStreamBuffer имеет значение threadLocal, каждый из них будет иметь свой собственный локальный буфер.Каждый поток получает данные, вызывает HandleData () и, после завершения, повторяет цикл.

Размер передаваемых данных составляет 2 ГБ.Таким образом, общая ожидаемая память будет не более (2 ГБ + размер байтового массива потока) * количество потоков.Максимальный размер потока массива должен составлять 4 ГБ (удвоение данных из-за изменения размера в памяти).Таким образом, ожидаемая общая куча будет 6 * 8 = 48 ГБ.Куча настроена для обработки гораздо больше (я пробовал до 300 ГБ), и все же эта проблема сохраняется.

public class DataHandler {
    private static ThreadLocal<ByteArrayOutputStream> byteArrayOutputStreamBuffer =
        new ByteArrayOutputStream();

    void HandleData(byte[] data) {
        ByteArrayOutputStream byteArrayOutputStream = byteArrayOutputStreamBuffer.get();
        File tempFile = new File(getFileName());
        try (FileOutputStream fileOutputStream = new FileOutputStream(tempFile)) {
            byteArrayOutputStream.write(data);
            fileOutputStream.write(byteArrayOutputStream.toByteArray());
        } finally {
            byteArrayOutputStream.reset();
        }
    }
}

Если я удаляю промежуточный ByteArrayOutputStream, то OOM не существует.Я пытаюсь найти объяснение, почему ByteArrayOutputStream вызывает OOM.

РЕДАКТИРОВАТЬ: я вижу, что toByteArray () также добавит еще 2 ГБ, поэтому общий объем будет 64 ГБ.

1 Ответ

0 голосов
/ 11 сентября 2018

A ByteArrayOutputStream может содержать не более Integer.MAX_VALUE - 8 байтов (на 8 байтов меньше 2 ГБ), поскольку он хранит свои данные в одном byte[], а длина массива ограничена этим значением.

Если вы попытаетесь ввести больше данных, вы получите OutOfMemomoryError.

Поскольку вы вводите столько данных, вероятно, так и происходит.

Вы не можете использовать ByteArrayOutputStream в таком случае.

Но зачем тебе это?Почему бы вам просто не сохранить FileOutputStream в ThreadLocal?

...