0

ファイル出力ストリームで圧縮、暗号化、およびチェックサムを行うコードがあります。以下はコードです-

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」オブジェクトは実際にどうなるのでしょうか? 言い換えると、「new」を使用して作成された 4 つのオブジェクトがありますが、同じ「os」変数に再割り当てされています。新しいオブジェクトの作成/機能自体が古いオブジェクトに内部的に依存しているため、理解するのが難しいと感じています。

4

4 に答える 4

3

オブジェクトがスタックを介して参照可能であり、それをメモリ内に置きたくない場合にのみ、メモリ リークが発生します。

例は次のようになります。

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 に設定するか、再割り当てするだけで、メモリを収集できます。

ラッピングの場合、「ルート」オブジェクトがなくなると、他のライブ参照がない限り、すべてのラッピング オブジェクトがガベージ コレクションの対象になります。そのため、開始方法が返されると、そこで作成されたすべてのオブジェクトを収集できるはずです。

于 2009-12-04T09:09:12.760 に答える
2

出力ストリームへのすべての参照は、ローカル変数のみです。したがって、start() が終了した後、ストリームへの参照は残っておらず、'Big GC' がクリーンアップします。

実際の eclipse SDK と実際の Java (6+) が手元にあることを本当に確認したい場合は、os.close() 行にブレークポイントを追加して、予期しないオブジェクトがストリームへの参照を保持しているかどうかを調べることができます。

于 2009-12-04T09:10:17.137 に答える
0

Java には自動ガベージ コレクション メカニズムがあるため、C++ でメモリ リークを引き起こす古いオブジェクトを解放しないことを心配する必要はありません。基本的に、 variable を使用して指さなくなったオブジェクトへのダングリング参照がないことを確認するだけで済みますos

于 2009-12-04T09:06:19.990 に答える