簡體   English   中英

GZIPInputStream 內存泄漏

[英]GZIPInputStream memory leakage

使用 GZIPInputStream 時出現 java.lang.OutOfMemoryError: Java heap space。 Java 進程在一段時間內運行良好,但一段時間后內存已滿。 我猜有一些引用沒有被 GC 處理,但可以真正找到代碼中的問題所在。 我已經將進程的內存增加到 3 GB,但肯定會在一段時間后填滿該內存。 真的是進步的,無論內存大小。 有沒有人知道如何改進我的代碼以防止內存泄漏?

public byte[] uncompress(byte[] msg) {
    byte[] buffer = new byte[4 * 1024];
    int length;

    try (GZIPInputStream gzis = new GZIPInputStream(new ByteArrayInputStream(msg));
         BufferedInputStream bis = new BufferedInputStream(gzis);
         ByteArrayOutputStream baos = new ByteArrayOutputStream()
    ) {
        while ((length = bis.read(buffer)) >= 0) {
            baos.write(buffer, 0, length);
        }

        final byte[] result = baos.toByteArray();
        return result;
    } catch (Exception e) {
    }
}

假設膨脹的流大於msg是合理的,因此如果您使用new ByteArrayOutputStream(msg.length)則可以幫助您的程序使用更少的重新分配。 此外,通過刪除 BufferedInputStream 和您自己的緩沖區來擺脫雙緩沖,只需調用transferTo分配單個內部緩沖區。

因此,如果您將其減少為以下內容,您的程序將執行更少的內存重新分配:

public byte[] uncompress(byte[] msg) throws IOException {
    try (GZIPInputStream gzis = new GZIPInputStream(new ByteArrayInputStream(msg));
         ByteArrayOutputStream baos = new ByteArrayOutputStream(msg.length)
    ) {
        gzis.transferTo(baos);

        return baos.toByteArray();
    }
}

但是,您仍然可能會遇到 OOM - 因為您的內存中可能有 3 個大byte[] 您可以對ByteArrayOutputStream內的預期最終長度使用更大的猜測大小,以確保它在膨脹時不會重新分配 - 例如: new ByteArrayOutputStream(msg.length * 4 / 3) 如果在toByteArray()發生 OOM,也可以使用子類讀取內部byte[]

更好的是,更改應用程序的結構以避免流的完整byte[]副本,並更改​​壓縮以支持調用者提供的 OutputStream。

public void uncompress(byte[] msg, OutputStream out) throws IOException

或者

public void  uncompress(InputStream msg, OutputStream out) throws IOException

我已經看到一些關於由 zlib 堆外內存分配引起的 Java OOM 的浮動(例如示例),這可能意味着您對傳統代碼不走運。

如果它只是您的代碼,您應該監視實時堆(嘗試JMC ),進行堆轉儲(或兩次)並檢查內容( Eclipse MAT可讓您區分兩個堆)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM