包装多个Outputstream对象时的Java Outputstream行为
我有一个对文件Outputstream进行压缩、加密和校验的代码。下面是代码-包装多个Outputstream对象时的Java Outputstream行为,java,memory-leaks,garbage-collection,object,outputstream,Java,Memory Leaks,Garbage Collection,Object,Outputstream,我有一个对文件Outputstream进行压缩、加密和校验的代码。下面是代码- private void start() { OutputStream os = null; try { os = new FileOutputStream("/some/file"); os = wrapAllRequiredTransforms(os); //Write to os } finally { os.close(
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变量。我想知道这是否会导致内存泄漏?创建的旧操作系统对象实际会发生什么情况?换言之,有4个对象使用new创建,但被重新分配给同一os变量。我发现很难理解,因为新的对象创建/运行本身是依赖于旧对象内部的。 < P> java有一个自动垃圾收集机制,所以你不必担心不释放那些会在C++中产生内存泄漏的旧对象。基本上,您只需确保没有对不再指向使用变量os的对象的悬空引用。这是Java中的标准做法,而且是安全的 发生的情况是,每个新对象在内部保留对传入对象的引用。此过程称为包装或委派。当您关闭最后一个操作系统时,它会将方法调用传递给包装的实例
这样,一次调用将关闭所有对象,释放最外层的操作系统将释放所有对象。只有当对象可通过堆栈引用且不再希望它位于内存中时,才会出现内存泄漏 例如:
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返回在中创建的所有对象,就应该能够收集这些对象。对outputstreams的所有引用都只是局部变量。因此,在start终止后,将不再有对流的引用,并且“大GC”将被清除
如果您确实想要确定,并且手头有一个实际的eclipse SDK和实际的Java 6+,那么您可以在os.close行中添加一个断点,并检查是否有一些意外的对象包含对您的流的引用。您的try/finally失败了。如果(比如)找不到文件会发生什么。使用获取;尝试{use;}最后{release;}。在这种情况下,类似于:final OutputStream rawOut=new FileOutputStream/some/file/;试试{final OutputStream out=wraprawOut;…}最后{rawOut.close;}。谢谢汤姆!是的,您是对的,这里没有处理错误条件,事实上,上面的代码片段在复制到程序时甚至不会编译。以上代码片段仅试图说明我试图理解的问题: