ThreadLocal<ByteArrayOutputStream> 导致 OutOfMemory
ThreadLocal<ByteArrayOutputStream> causes OutOfMemory
当我的 class 结构如此时,我最终遇到了 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。
A ByteArrayOutputStream
最多可以容纳 Integer.MAX_VALUE - 8
字节(8 字节小于 2Gb),因为它将其数据存储在单个 byte[]
中,并且数组长度限于此值。
如果您尝试放入更多数据,它会抛出 OutOfMemomoryError
。
由于您输入了这么多数据,所以可能会发生这种情况。
在这种情况下,您不能使用 ByteArrayOutputStream
。
但是你为什么需要它?为什么不直接将 FileOutputStream
存储在 ThreadLocal 中?
当我的 class 结构如此时,我最终遇到了 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。
A ByteArrayOutputStream
最多可以容纳 Integer.MAX_VALUE - 8
字节(8 字节小于 2Gb),因为它将其数据存储在单个 byte[]
中,并且数组长度限于此值。
如果您尝试放入更多数据,它会抛出 OutOfMemomoryError
。
由于您输入了这么多数据,所以可能会发生这种情况。
在这种情况下,您不能使用 ByteArrayOutputStream
。
但是你为什么需要它?为什么不直接将 FileOutputStream
存储在 ThreadLocal 中?