簡體   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