代码之家  ›  专栏  ›  技术社区  ›  Keshav

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

  •  0
  • Keshav  · 技术社区  · 16 年前

    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方法中使用不同的对象(使用new创建)重新分配“os”变量。我想知道这是否会导致内存泄漏?创建的旧“os”对象实际会发生什么情况?换言之,有4个对象使用“new”创建,但被重新分配给同一个“os”变量。我发现很难理解,因为新对象的创建/功能本身在内部依赖于旧对象。

    4 回复  |  直到 8 年前
        1
  •  2
  •   Aaron Digulla    16 年前

    发生的情况是,每个新对象在内部保留对传入对象的引用。这个过程称为“包装”或“委托”。当你关闭最后一个 os

    通过这种方式,一次呼叫将关闭它们,并释放最外层 全部释放。

        2
  •  3
  •   TofuBeer    16 年前

    只有当对象可以通过堆栈引用,并且不再希望它位于内存中时,才会出现内存泄漏。

    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 ...
        }
    }
    

    解析器不再使用,但仍然可以访问,因此从技术上讲,它是一个内存泄漏(您不想再使用的内存,但垃圾收集器还不能回收)。

        3
  •  2
  •   Andreas Dolk    16 年前

    对outputstreams的所有引用仅为局部变量。因此,在start()终止后,将不再剩下对流的引用,“大GC”将被清除。

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

        4
  •  0
  •   Joy Dutta    16 年前

    os .