[英]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.