带有ByteArrayOutputStream.toByteArray()的OOM

时间:2017-09-27 07:35:31

标签: java

我想解压缩已经使用byte[]压缩的Deflater(因为我的文件是压缩的),但是在使用inflater解压缩时,我试图使用{{1}来获取字节数组反过来抛出outputStream.toByteArray(),请建议一些避免OOM的解决方案。

OOM

注意:我知道public static byte[] decompress(byte[] data){ Inflater inflater = new Inflater(); inflater.setInput(data); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length); byte[] buffer = new byte[data.length+100]; while (!inflater.finished()) { int count = inflater.inflate(buffer); outputStream.write(buffer, 0, count); } outputStream.close(); byte[] output = outputStream.toByteArray(); 的内部实现,但没有获得任何替代方案。

2 个答案:

答案 0 :(得分:2)

您的总体目标是什么?

如果你要解压缩内存中的所有东西(不能改变“解压缩”方法的返回值和参数),那么你确实需要添加更多的内存。

但是如果你需要 - 例如 - 解压缩文件,那么在适当的流使用情况下你的程序应该能够用很少的内存解压缩任意大的文件(从压缩文件读取一点,解压缩,写入结果到输出文件,重复它......)。

Compressing and decompressing large size data in java?

答案 1 :(得分:0)

如果你必须在内存中解压缩,并且你有足够的内存用于压缩输入和膨胀输出,但不是更多,那么你应该考虑ByteArrayOutputStream.toByteArray()创建一个新的字节数组,有效地使内存加倍需要(直到byteArrayOutputStream被垃圾收集)。

所以,我认为以下是可能的,并且以更高的CPU使用价格降低内存消耗:

  1. 通过流媒体对输入进行充气,并记住充气数据的确切大小(假设为999999999)。
  2. 创建ByteArrayOutputStream的子类,以便访问它的内部缓冲区。
  3. 创建一个子类的实例,其中包含膨胀数据的确切大小(MyByteArrayOutputStream(999999999)),并将其传递给inflater。
  4. 在inflater完成后,
  5. 返回内部缓冲区,当时该缓冲区保存了膨胀的数据。
  6. 由于子类在开头创建了正确大小的内部缓冲区,因此在通缩期间不会复制它。此外,由于内部缓冲区的大小合适,您可以安全地将其传递给调用者而无需复制。这样你的内存需求只是输入+输出字节数组大小加上一些开销(但不输入+ 2 *输出)。