首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >包装多个Outputstream对象时的Java outputstream行为

包装多个Outputstream对象时的Java outputstream行为
EN

Stack Overflow用户
提问于 2009-12-04 17:01:37
回答 4查看 2.2K关注 0票数 0

我有一个代码,可以对文件输出流进行压缩、加密和校验。以下是代码-

代码语言:javascript
复制
private void start() {
    OutputStream os = null;
    try {
        os = new FileOutputStream("/some/file");
        os = wrapAllRequiredTransforms(os);

        //Write to os
    } finally {
        os.close();
    }
}

private wrapAllRequiredTransforms(OutputStream os) {
    if(checkSumRequired) {
        os = wrapOStreamWithCheckSum(os);
    }

    if(encryptionRequired) {
        os = wrapOStreamWithCipher(os);
    }

    if(compressRequired) {
        os = wrapOStreamWithCompress(os);
    }
}

private OutputStream wrapOStreamWithCheckSum(OutputStream os) throws Exception {
    os = new DigestOutputStream(os, MessageDigest.getInstance("MD5"));
    return os;
}

private OutputStream wrapOStreamWithCipher(OutputStream os) throws Exception {
    SecretKeySpec secretKeySpec = new SecretKeySpec(//SomeKey, encryptionAlgorithm);
    Cipher cipher = Cipher.getInstance(encryptionAlgorithm); 
    cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
    return new CipherOutputStream(os, cipher);
}

private OutputStream wrapOStreamWithCompress(OutputStream os) throws Exception {
    return new GZIPOutputStream(os);
}

正如您在这里看到的,我包装了"os“对象以进行加密、压缩等操作,然后在wrapOStreamWithCheckSum、wrapOStreamWithCipher和wrapOStreamWithCompress方法中使用不同的对象(使用新方法创建)重新分配"os”变量。我想知道这是否会导致内存泄漏?创建的较早的"os“对象到底会发生什么?换句话说,有4个对象使用"new“创建,但被重新分配给相同的"os”变量。我发现这很难理解,因为新对象的创建/运行本身在内部依赖于旧对象。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2009-12-04 17:08:24

这是Java和safe中的标准实践。

发生的情况是,每个新对象都会在内部保留对传入对象的引用。这个过程被称为“包装”或“委托”。当您关闭最后一个os时,它会将方法调用传递给包装的实例。

这样一来,一个调用就会关闭它们,释放最外层的os就会释放所有它们。

票数 2
EN

Stack Overflow用户

发布于 2009-12-04 17:09:13

只有当对象可通过堆栈引用,并且您不再希望它在内存中时,才会发生内存泄漏。

示例如下所示:

代码语言:javascript
复制
public class Main
{
    private static CommandLineArgumentParser parser;

    public static void main(final String[] argv)
    {
        parser = new CommandLineArgumentParser(argv);
        ... use the parser
        ... never use the parser again ....
        ... do a bunch of work ...
    }
}

解析器不再使用,但它仍然可以访问,因此从技术上讲,它是内存泄漏(您不再希望使用但仍无法被垃圾收集器回收的内存)。

要使它不再使用,您需要做的就是将它设置为null或重新分配它,然后就可以收集内存了。

在包装的情况下,一旦“根”对象消失,并且只要没有其他活动引用,所有包装对象都将有资格进行垃圾回收。因此,一旦start meoth返回所有在其中创建的对象,就应该能够被收集。

票数 3
EN

Stack Overflow用户

发布于 2009-12-04 17:10:17

所有对输出流的引用都只是局部变量。因此,在start()终止后,将不再有对剩余流的引用,“Big GC”将被清除。

如果您真的想确保手头有一个实际的eclipse SDK和实际的Java (6+),那么可以在os.close()行中添加一个断点,并检查是否有一些意外的对象包含对流的引用。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1845737

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档