ThreadLocal <bytearrayoutputstream>导致内存不足

时间:2018-09-11 00:10:54

标签: java out-of-memory thread-local

当我的类结构如下时,我最终遇到OutOfMemory错误。

DataHandler由8个线程的固定池调用(没有外部线程池管理。固定池创建一次,执行一次,并且如果一个线程死亡,则不创建新线程)。一次有多个线程调用DataHandler,但是由于byteArrayOutputStreamBuffer是threadLocal,因此每个线程都有自己的本地缓冲区。每个线程获取数据,调用HandleData(),并在完成后重复循环。

传递的数据大小为2 GB。因此,预计将占用的总内存最多为(2 GB +字节数组流的大小)*线程数。数组流的最大大小应为4 GB(由于内存大小的调整,数据量增加了一倍)。因此,预期的总堆为6 * 8 = 48 GB。堆配置为可以处理更多(我已经尝试了高达300 GB),但是这个问题仍然存在。

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 GB,因此总数将是64 GB。

1 个答案:

答案 0 :(得分:1)

ByteArrayOutputStream最多可以容纳Integer.MAX_VALUE - 8个字节(比2Gb少8个字节),因为它将数据存储在单个byte[]中,并且数组长度限制为该值。

如果您尝试放入更多数据,则会抛出OutOfMemomoryError

由于要输入大量数据,因此可能就是这样。

在这种情况下,您不能使用ByteArrayOutputStream

但是您为什么需要它?您为什么不只将FileOutputStream存储在ThreadLocal中?