使用 ByteArrayOutputStream (BAOS) 累積大量資料時,可能在兩個不同位置拋出 OutOfMemoryError (OOM)。
Integer.MAX_VALUE (位置 1: write())byte[] buf,count 為 int。newSize = Math.max(buf.length << 1, count + len)。count + len > Integer.MAX_VALUE (2^31-1) 時,newSize 溢位變負,或 Arrays.copyOf 拋出 OutOfMemoryError: Requested array size exceeds VM limit。toByteArray() 複製陣列失敗 (位置 2)toByteArray() 執行 Arrays.copyOf(buf, count),需再分配一個 count 大小的新陣列。OutOfMemoryError: Java heap space。buf 已持有資料,count 正確,可直接用 buf (需配合 count 判斷有效長度)。public class BAOSOOMDemo {
static class MyBAOS extends ByteArrayOutputStream {
public byte[] getBuf() { return buf; }
public int getCount() { return count; }
}
public static byte[] mapToBytes(Map,?> map) {
try (MyBAOS memOut = new MyBAOS();
ObjectOutputStream out = new ObjectOutputStream(memOut)) {
out.writeObject(map);
out.flush();
System.out.println("count=" + memOut.getCount() + ", buf.length=" + memOut.getBuf().length);
// 避免 toByteArray() 第二次分配
// return Arrays.copyOf(memOut.getBuf(), memOut.getCount()); // 手動複製
return memOut.toByteArray(); // 可能 OOM
} catch (IOException e) { throw new RuntimeException(e); }
}
public static void main(String[] args) {
Map map = new HashMap<>();
// 測試 300 萬條目,視記憶體調整
for (int i=0; i<3000000; ++i)
map.put(String.valueOf(i), "abcdefghijklmnopqrstuvwxyz".repeat(10));
byte[] data = mapToBytes(map);
System.out.println("Final size: " + data.length);
}
}
FileOutputStream 或分段序列化。toByteArray():若下游接受 InputStream,用 new ByteArrayInputStream(buf, 0, count) 包裝內部緩衝區 (需繼承暴露 buf/count)。-Xmx4g 等,治標不治本。ByteBuffer (支援直接記憶體)、MappedByteBuffer (記憶體映射檔案)、Netty CompositeByteBuf。ByteArrayOutputStream 適用於中小型資料緩衝 (MB 級)。大資料量 (GB 級) 必須串流式處理,避免全量駐留堆記憶體。