Клонирането на обект за еднократна употреба ще причини ли изтичане на памет в C#?

Проверете този код:

.. 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 is ICloneable, IDisposable in C#.

Освен това избягвайте изтичане на памет, за обект за еднократна употреба обикновено използвайте using, след което обектът ще бъде изхвърлен от системата автоматично, без значение колко грешен е вашият код.

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

Въпросът ми е: имам imageObject обект, след което го използвам Clone() метод, клонирам нов обект и го давам на старата обектна променлива. Това ще причини ли един (или клонираният, или оригиналният) обект да отиде никъде и никога да не бъде изхвърлен, изтичане на памет.

[РЕДАКТИРАНЕ]

Изглежда повечето мнения са 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
    }

и трябва да е правилно Разполагайте с ресурсите.


person Eric Yin    schedule 08.01.2012    source източник
comment
Защо го копираш два пъти?   -  person SLaks    schedule 09.01.2012


Отговори (5)


using просто извиква Dispose в finally блок.
Докато извиквате Dispose някъде във всички кодови пътища, всичко е наред.

Ако не се обадите на Dispose, GC евентуално ще го изхвърли вместо вас, но това може да доведе до конкуренция за ресурси.

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

person SLaks    schedule 08.01.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();
}
person scott.korin    schedule 08.01.2012

Да, това може да е теч.

Ако правите копие на обект за еднократна употреба (във вашия случай Bitmap), трябва незабавно да изхвърлите екземпляра, който вече не ви е необходим.

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

person DXM    schedule 08.01.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);
  }
}
person Guffa    schedule 08.01.2012
comment
Смятате ли, че създавате нов оригинален обект, по-късно го изхвърлете. Това няма нищо общо с оригиналния обект и клонирания обект? - person Eric Yin; 09.01.2012
comment
@EricYin: Да, така е. Оригиналният обект се изхвърля, а клонингът се съхранява в собствеността. - person Guffa; 09.01.2012

Ако приемем, че Clone() върши работата си правилно, ще ви даде 2 обекта за еднократна употреба за управление. И двете трябва да бъдат Disposed().

Така че не мисля, че ще реши проблема ви.

Не е необичайно методът да върне IDisposable обект, просто трябва да осигурите (безопасно от изключения) управление на ресурсите на по-високо ниво. Правете го внимателно.

person Henk Holterman    schedule 08.01.2012