2016-04-10 92 views
0

我正在開發一個Web應用程序,我需要將大約500mb的大文件加密到圖像。第一次代碼工作正常,但在此之後,我的服務器給出錯誤java.lang.OutOfMemoryError:Java堆空間。我正在使用netbeans和glassfish服務器。我也增加了堆的大小。java.lang.OutOfMemoryError:com.sun.crypto.provider.CipherCore.update上的Java堆空間

byte j[] = key.getBytes(); 
    SecretKeySpec kye = new SecretKeySpec(j, "AES"); 
    Cipher enc = Cipher.getInstance("AES"); 
    enc.init(Cipher.ENCRYPT_MODE, kye); 
    FileOutputStream output = new FileOutputStream("xyz.mkv"); 
    CipherOutputStream cos = new CipherOutputStream(output, enc); 
    byte[] buf = new byte[104857600]; 
    int read; 
    while ((read = file.read(buf)) != -1) { 
     cos.write(buf, 0, read); 
    } 
    output.flush(); 
    buf = null; 
    file.close(); 
    cos.close(); 

我不知道發生了什麼問題,請幫忙。 這裏是堆棧跟蹤..

Warning: StandardWrapperValve[DocEncrypt]: Servlet.service() for  
servlet DocEncrypt threw exception 
java.lang.OutOfMemoryError: Java heap space 
at java.util.Arrays.copyOf(Arrays.java:3236) 
at com.sun.crypto.provider.CipherCore.update(CipherCore.java:666) 
at com.sun.crypto.provider.AESCipher.engineUpdate(AESCipher.java:371) 
at javax.crypto.Cipher.update(Cipher.java:1832) 
at javax.crypto.CipherOutputStream.write(CipherOutputStream.java:158) 
+1

請向我們展示堆棧跟蹤。 –

+0

@StephenC我已經添加了堆棧跟蹤。 –

回答

1

根據堆棧跟蹤和源代碼,它看起來像加密堆棧在內部分配一個緩衝區,其大小與您用write調用編寫的塊相同。

您已選擇使用非常大的緩衝區;即104,857,600字節。所以密碼棧本身需要分配一個非常大的緩衝區。

解決方案:

  1. 你可以增加堆大小。
  2. 建議:您可以將緩衝區大小減小到更合理的值。我會推薦1MiB或更少。 (大於此值,緩衝區的大小會使性能上的好處很小......)
+0

它解決了這個問題,但是我怎樣才能使這個算法的性能更好呢 –

+0

我想不出一種更快的方法,用Java來加密是很貴的,你可以用原生的(第三方)庫或獨立的native公用事業。 –

+0

感謝您的幫助。 –

0

簡短的回答,你需要增加Java虛擬機FE的最大內存分配池:當你啓動應用程序-Xmx2048m

欲瞭解更多詳情檢查this amswer

+0

可能。他也可以用更少的記憶來做他想做的事情。例如,一個100Mb的緩衝區似乎......揮之不去。 –

+0

嗯,但會使用較小的緩衝區更改任何東西(內存明智)?它只會創建更小的byte []數組,最終會變得幾乎相同,對嗎?無論如何,我認爲GC的速度不會太快。 – grebesche

+0

當然會。如果您使用較小的緩衝區,則這是緩衝區的較小堆節點。重要的不是GC的速度。第一個近似值是所有可到達對象的總大小,用於確定何時空間不足。 –