繁体   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