Будет ли клон одноразового объекта вызывать утечку памяти в C #? - PullRequest
6 голосов
/ 09 января 2012

Проверьте этот код:

.. class someclass : IDisposable{
    private Bitmap imageObject;
    public void ImageCrop(int X, int Y, int W, int H)
    {
        imageObject = imageObject.Clone(new Rectangle(X, Y, W, H), imageObject.PixelFormat);
    }
    public void Dispose()
    {
        imageObject.Dispose();
    }
}

Bitmap - это ICloneable, IDisposable в C #.

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

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

У меня вопрос: у меня есть объект imageObject, затем я использую его Clone() метод клонирования нового объекта и передачи его в старую переменную объекта. Это приведет к тому, что один (клонированный или исходный) объект никуда не денется и никогда не будет уничтожен, что приведет к утечке памяти.

[EDIT]

Кажется, что большинство мнений Clone вызывают дополнительный объект, старый должен быть Dispose()

Вот новый код:

    public void ImageCrop(int X, int Y, int W, int H)
    {
            // We have 1 object: imageObject
            using (Bitmap croppedImage = imageObject.Clone(new Rectangle(X, Y, W, H), imageObject.PixelFormat))
            {
                    // We have 2 objects: imageObject and croppedImage
                    imageObject.Dispose(); // kill one, only croppedImage left
                    imageObject = new Bitmap(croppedImage); // create one, now 2 objects again
            } // the using() will kill the croppedImage after this
            // We have 1 object: imageObject
    }

и оно должно быть правильным. Утилизировать ресурсы.

Ответы [ 6 ]

2 голосов
/ 09 января 2012

Я не могу сказать наверняка, но если вы боитесь, что это может, почему бы не клонировать изображение в новую переменную, утилизировать оригинал, а затем переназначить:

public bool ImageCrop(int X, int Y, int W, int H)
{     
    Bitmap croppedImage = imageObject.Clone(new Rectangle(X, Y, W, H), imageObject.PixelFormat);
    imageObject.Dispose();
    imageObject = new Bitmap(croppedImage);
    croppedImage.Dispose();
}
2 голосов
/ 09 января 2012

using просто вызывает Dispose в блоке finally.
Пока вы вызываете Dispose где-то во всех путях кода, все в порядке.

Если вы не позвоните Dispose, GC в конечном итоге утилизирует его для вас, но это может привести к конфликту ресурсов.

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

1 голос
/ 09 января 2012

Ключом к предотвращению утечек ресурсов или ошибок преждевременной утилизации является обеспечение того, чтобы у каждого IDisposable объекта всегда был один четко определенный владелец, отвечающий за его утилизацию.Иногда объект будет предоставлять метод, с помощью которого он станет владельцем переданного объекта.Если владелец объекта передает его такому методу, первоначальный владелец объекта должен не распоряжаться им.В противном случае владелец объекта должен избавиться от объекта перед уничтожением его последней ссылки на него.

Если someClass принадлежит ImageObject, то он, вероятно, должен уничтожить этот объект, прежде чем уничтожить ссылку наЭто.С другой стороны, если объект содержит единственную ссылку на другой объект, клонирование удерживаемого объекта с целью переназначения исходной ссылки выглядит как запах кода.Я не знаю, как изначально назначается ImageObject, но может показаться, что он должен быть создан внутри вашего объекта или клонирован на основе переданного объекта изображения.В любом случае вы должны иметь возможность достаточно контролировать тип переданного изображения, чтобы выбрать тип, который можно обрезать без необходимости (повторного) клонирования.

1 голос
/ 09 января 2012

Предполагая, что Clone () выполняет свою работу должным образом, вы получите 2 доступных объекта для управления.Оба должны быть утилизированы ().

Так что я не думаю, что это решит вашу проблему.

Обычно метод возвращает объект IDisposable, вы просто должны обеспечить (исключительное безопасное) управление ресурсами на более высоком уровне.Делай так осторожно.

1 голос
/ 09 января 2012

Память не протекает в управляемом коде, но вы можете вызвать утечку ресурса. Растровое изображение представляет собой обертку вокруг объекта более низкого уровня в Windows, и его можно использовать для правильной очистки объекта более низкого уровня. Если вы оставляете объекты неиспользуемыми, они обычно должны утилизироваться сборщиком мусора через некоторое время, но нет никакой гарантии, что они действительно будут утилизированы.

Клонирование изображения создает новый объект, который должен быть расположен внутри себя. Вы должны избавиться от исходного изображения, когда оно будет заменено клоном. Для этого вы можете использовать ключевое слово using:

public bool ImageCrop(int X, int Y, int W, int H) {
  using (Bitmap original = imageObject) {
    imageObject = original.Clone(new Rectangle(X, Y, W, H), imageObject.PixelFormat);
  }
}
1 голос
/ 09 января 2012

Да, это может быть утечка.

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

использование ключевого слова - это просто удобство при ручной попытке-наконец и вызове Dispose (). Если в вашей ситуации вы не можете использовать 'using', просто используйте блоки try-finally и убедитесь, что свисающий ресурс очищен.

...