繁体   English   中英

Java Inflater 有时会无限循环

[英]Java Inflater will loop infinitely sometimes

在我的应用程序中,我尝试使用 java 的 Inflater/Deflater 类压缩/解压缩字节数组。 这是我最初使用的代码的一部分:

   ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length);  
   byte[] buffer = new byte[1024];  
   while (!inflater.finished()) {  
       int count = inflater.inflate(buffer);  
       outputStream.write(buffer, 0, count);  
   }  

然后在我部署代码后,它会随机(非常罕见)导致整个应用程序挂起,当我进行线程转储时,我可以识别出一个线程挂起

    at java.util.zip.Inflater.inflateBytes(Native Method)
    at java.util.zip.Inflater.inflate(Inflater.java:259)
      - locked java.util.zip.ZStreamRef@fc71443
    at java.util.zip.Inflater.inflate(Inflater.java:280)

它不经常发生。 然后我到处搜索,发现它可能是在充气器中传递的一些空字节数据,而finished()永远不会返回true。

所以我使用了一种解决方法,而不是使用

while (!inflater.finished()) 

为了确定它是否完成,我使用了

while (inflater.getRemaining() > 0)

但它又发生了。 现在它让我想知道导致问题的真正原因是什么。 inflater 中不应该传递任何空数组,即使传递了,为什么 getRemaining() 方法没有中断 while 循环? 有人可以帮忙吗? 真是烦死我了。

对同样的问题感到困惑,我找到了这个页面。

这是我的解决方法,它可能会有所帮助:

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
while (!inflater.finished()) {
    int i = inflater.inflate(buffer);
    if (i == 0) {
        break;
    }
    byteArrayOutputStream.write(buffer, 0, i);
}

对Javadoc 充气

将字节解压缩到指定的缓冲区中。 返回未压缩的实际字节数。 返回值 0 表示应调用 NeedsInput() 或 NeedsDictionary() 以确定是否需要更多输入数据或预设字典。 在后一种情况下, getAdler() 可用于获取所需字典的 Adler-32 值。

所以@Wildo Luo 检查是否返回 0 肯定是正确的。

byte[] buffer = new byte[1024];  
while (!inflater.finished()) {  
    int count = inflater.inflate(buffer);  
    if (count != 0 ) {
       outputStream.write(buffer, 0, count);  
    } else {
       if (inflater.needsInput()) { // Not everything read
           inflater.setInput(...);
       } else if (inflater.needsDictionary()) { // Dictionary to be loaded
           inflater.setDictionary(...);
       }
    }
}
inflater.end();

我只能想象其他地方的代码并不完全正确,也许是压缩大小。 最好先检查通用代码。 Inflater(boolean nowrap)需要一个额外的字节,即end()调用。 异常处理(try-finally)。 等等。

对于未知数据,未知事件:使用 try-catch,查找压缩数据以检查它是否是基于数据的错误,并测试任何解决方案。

遇到同样的问题...

我确定的是:

  1. 我有一个无限循环,保证打印日志。
  2. inflater.inflate返回 0,输出缓冲区大小为 0。

我的循环是这样的(Hive ORC 代码):

while (!(inflater.finished() || inflater.needsDictionary() ||
             inflater.needsInput())) {
      try {
        int count = inflater.inflate(out.array(),
                                     out.arrayOffset() + out.position(),
                                     out.remaining());
        out.position(count + out.position());
      } catch (DataFormatException dfe) {
        throw new IOException("Bad compression data", dfe);
      }
    }

消耗完输出缓冲区并且其剩余大小为 0 后,循环将无限运行。

但我不确定是orc 还是zlib 导致了这个。 在兽人方面,它用相同的压缩缓冲区大小填充原始数据然后进行压缩,所以理论上我不可能得到大于缓冲区大小的压缩块。 可能性可能是 zlib 或硬件。

话虽如此,当count == 0很危险时中断循环,因为充气机中可能仍有未压缩的数据。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM