Поведение Java Outputstream при переносе нескольких объектов outputtream - PullRequest
0 голосов
/ 04 декабря 2009

У меня есть код, который выполняет сжатие, шифрование и контрольную сумму для выходного потока файла. Ниже приведен код-

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" для шифрования, сжатия и т. Д., А затем переназначаю переменную "os" другим объектом (созданным с помощью new) внутри каждого из методов wrapOStreamWithCheckSum, wrapOStreamWithCipher и wrapOStreamWithCompress , Мне было интересно, если это приводит к утечке памяти случайно? Что на самом деле произойдет с созданными более старыми объектами "os"? Перефразируя, есть 4 объекта, созданных с использованием «new», но переназначаемых той же самой переменной «os». Мне трудно понять, потому что само создание / функционирование нового объекта зависит от старого объекта внутренне.

Ответы [ 4 ]

3 голосов
/ 04 декабря 2009

Вы получаете утечки памяти только тогда, когда объект доступен через стек, и вы больше не хотите, чтобы он был в памяти.

Примером будет что-то вроде этого:

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

Синтаксический анализатор больше не используется, но он все еще доступен, так что с технической точки зрения это утечка памяти (память, которую вы больше не хотите использовать, но которую сборщик мусора еще не может исправить).

Чтобы он больше не использовался, все, что вам нужно сделать, это установить его на ноль или переназначить его, тогда память можно будет собрать.

В случае переноса, когда «корневой» объект исчезает, и пока нет других активных ссылок, все объекты переноса будут иметь право на сборку мусора. Таким образом, как только стартовый зуб вернет все объекты, созданные в нем, их можно будет собрать.

2 голосов
/ 04 декабря 2009

Все ссылки на ваши выходные потоки являются только локальными переменными. Поэтому после завершения start () больше не остается ссылок на потоки, и «Big GC» очистится.

Если вы действительно хотите быть уверенным и иметь под рукой фактический SDK затмения и реальный Java (6+), вы можете добавить точку останова в строку os.close () и проверить, если некоторые неожиданные объекты содержат ссылки на поток.

2 голосов
/ 04 декабря 2009

Это стандартная практика на Java и безопасная.

Что происходит, так это то, что каждый новый объект хранит внутри себя ссылку на переданный. Этот процесс называется «переносом» или «делегированием». Когда вы закрываете последний os, он передает вызов метода в упакованный экземпляр.

Таким образом, один вызов закроет их все, а освобождение самого внешнего os освободит их всех.

0 голосов
/ 04 декабря 2009

Java имеет механизм автоматической сборки мусора, поэтому вам не нужно беспокоиться о том, чтобы не освобождать старые объекты, которые в противном случае могли бы вызвать утечку памяти в C ++. По сути, вам нужно только убедиться, что нет никаких висящих ссылок на объекты, на которые вы больше не указываете, используя переменную os.

...