我有一个代码可以对文件输出流进行压缩、加密和校验。以下是代码-
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”变量。我发现很难理解,因为新对象的创建/功能本身在内部依赖于旧对象。
最佳答案
只有当对象可通过堆栈引用并且您不再希望它位于内存中时,才会出现内存泄漏。
一个例子是这样的:
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 或重新分配它,然后即可回收内存。
在包装的情况下,一旦“根”对象消失,并且只要没有其他 Activity 引用,所有包装对象都将有资格进行垃圾回收。因此,一旦启动方法返回,其中创建的所有对象就应该能够被收集。
关于包装多个输出流对象时的 Java 输出流行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1845737/