Java: Memory efficient ByteArrayOutputStream

我在磁盘中有一个40MB的文件,我需要使用字节数组将其“映射”到内存中。

起初,我认为将文件写入ByteArrayOutputStream是最好的方法,但我发现在复制操作期间的某个时候需要大约160MB的堆空间。

有人知道在不使用三倍于RAM文件大小的情况下执行此操作的更好方法吗?

更新:感谢您的回答。我注意到我可以减少内存消耗,告诉ByteArrayOutputStream初始大小比原始文件大一点(使用与我的代码强制重新分配的确切大小,必须检查原因)。

还有另一个高内存点:当我用ByteArrayOutputStream.toByteArray获得byte[]时。看看它的源代码,我可以看到它正在克隆数组:

public synchronized byte toByteArray()[] {
    return Arrays.copyOf(buf, count);
}

我想我可以扩展ByteArrayOutputStream并重写此方法,以便直接返回原始数组。考虑到流和字节数组不会多次使用,这里是否存在任何潜在危险?


答案 1

MappedByteBuffer可能是你要找的。

不过,我很惊讶需要如此多的RAM来读取内存中的文件。您是否以适当的容量构建了?如果没有,流可以在接近 40 MB 的末尾时分配一个新的字节数组,这意味着,例如,您将拥有 39MB 的完整缓冲区和两倍大小的新缓冲区。而如果流具有适当的容量,则不会有任何重新分配(更快),也不会浪费内存。ByteArrayOutputStream


答案 2

ByteArrayOutputStream只要在构造函数中指定适当的大小,就应该没问题。当您调用 时,它仍会创建一个副本,但这只是暂时的。你真的介意记忆短暂上升很多吗?toByteArray

或者,如果您已经知道要开始的大小,则可以创建一个字节数组,然后从该缓冲区中重复读取,直到获得所有数据。FileInputStream


推荐