2011-06-08 50 views
3

在我的一個項目中,我不斷壓縮小塊數據。 現在我發現jvm然後增長到6GB內存(駐留(RES)RAM,不共享或虛擬等),然後因內存不足而死亡。 這就好像垃圾收集器從不運行或者如此。 我已經拿出相關的代碼並粘貼在下面。當我運行它(java6,32位linux)時,它增長到1GB內存。 任何人都知道如何減少內存使用量?由java過度使用內存

import java.util.Random; 
import java.util.zip.Deflater; 
import java.util.zip.Inflater; 

class test { 
    int blockSize = 4096; 
    Random r = new Random(); 

    public test() throws Exception { 
     blockSize = 4096; 
     byte [] data = new byte[blockSize]; 
     for(int index=0; index<blockSize; index++) 
      data[index] = (byte)r.nextInt(); 

     for(long cnt=0; cnt<1000000; cnt++) { 
      byte [] result = compress(data); 
      if (result != null) 
       data[0] = result[0]; 
     } 
    } 

    byte [] compress(byte [] in) { 
     assert in.length == blockSize; 

     Deflater compresser = new Deflater(); 
     compresser.setInput(in); 
     compresser.finish(); 
     byte [] out = new byte[in.length]; 
     int outLen = compresser.deflate(out); 

     if (outLen < blockSize) { 
      byte [] finalOut = new byte[outLen]; 
      System.arraycopy(out, 0, finalOut, 0, outLen); 
      return finalOut; 
     } 

     return null; 
    } 

    public static void main(String [] args) throws Exception { 
     new test(); 
    } 
} 
+2

該死的,這總是發生:我一直在尋找答案的小時,所以我發佈了一個問題的地方。然後突然在5分鐘內我自己找到了答案。 解決方法是...在壓縮數據後調用壓縮器的end()! – 2011-06-08 06:32:09

+2

請發佈這個答案。通過這種方式,它可以被投票,未來的這個問題的訪問者會更容易找到它。 – 2011-06-08 06:51:42

回答

6

好,Folkert麪包車赫斯登解決自己的問題,而是要總結:

早在compress(byte [] in) - 方法,我們創造一個java.util.zip.Deflater

我們使用Deflater來做一些事情,然後我們離開compress()-方法。我們放棄了對deflater-變量的引用。此時,Deflater不再使用,並且正在等待被垃圾收集器殺死。

Deflater分配既Java堆內存C/C++ /機堆存儲器。由Deflater分配的本地堆內存將保留到垃圾收集器調用Deflater.finalize - 方法。如果垃圾收集器運行速度不夠快(可能有大量免費的Java堆內存),那麼我們可能會用完C/C++堆內存。如果發生這種情況,我們會得到「內存不足」 - 錯誤。

Oracle錯誤報告JDK-4797189可能與此有關。它包含的代碼片段說明和重現問題:

public class Bug { 
    public static void main(String args[]) { 
     while (true) { 
      /* If ANY of these two lines is not commented, the JVM 
      runs out of memory */ 
      final Deflater deflater = new Deflater(9, true); 
      final Inflater inflater = new Inflater(true); 
     } 
    } 
} 

解決的辦法是,當你調用Deflater.end() - 方法(或Inflater.end())完成以釋放資源。

-1

好吧,在我看來,代碼中沒有內存泄漏,所以它實際上似乎VM不是GC-ing字節數組。

「誰知道如何減少內存使用量?」
嗯,我會嘗試用

byte firstByteOfDataWhichIsCompressedAndThenUncompressed(byte [] in) { ... } 

其具體返回未壓縮數組的第一個字節,而不是整個數組。我知道,這是一個可怕的方法名稱,我希望你會找到一個更好的方法。

下面的代碼

for(long cnt=0; cnt<1000000; cnt++) { 
     byte [] result = compress(data); 
     if (result != null) 
      data[0] = result[0]; 
    } 

將成爲

for(long cnt=0; cnt<1000000; cnt++) 
     data[0] = firstByteOfDataWhichIsCompressedAndThenUncompressed(data); 
+0

確實存在泄漏,請參閱Folkbert的評論 - 他錯過了end() - 它可能是本機內存泄漏而非Java,因此不需要GC。 – 2011-06-08 14:34:26