Как c # обращается с памятью - PullRequest
2 голосов
/ 15 января 2010

У меня есть класс "skImage". У этого класса есть закрытая переменная (с открытым свойством, которое ее выставляет)

private Image _capturedImage;  

конструктор этого класса выглядит так:

   public skImage(Image captured) {

            _capturedImage = captured;

        }

Он также имеет следующий метод:

public bool Invert() {

        Bitmap b = new Bitmap(_capturedImage);

        unsafe {
         //random code not relevant.
        }

        _capturedImage = b;
        b.Dispose();
        return true;
    }

и затем у него есть метод save (), который просто вызывает:

  _capturedImage.Save(_saveFullLocation);

Теперь, если я запускаю метод инвертирования и затем пытаюсь вызвать save, он выдает исключение (параметр недействителен). После поиска в Google это исключение кажется, что я избавляюсь от изображения. Я вижу, что я располагаю буквой «б» после метода инвертирования.

Мой вопрос таков: когда я делаю _capturedImage = b, означает ли это, что обе переменные теперь содержат одну ссылку на объект? Я этого не хочу. Я хочу, чтобы b было уничтожено, чтобы освободить память, чтобы ГХ мог ее собрать. Как передать b в _capturedImage и уничтожить b.

спасибо

Ответы [ 5 ]

3 голосов
/ 15 января 2010

означает ли это, что обе переменные теперь содержат одну ссылку на объект?

Да. Тем не менее, ссылка является только ссылкой - она ​​не стоит много памяти.

Я хочу, чтобы b был уничтожен

Нельзя уничтожить ссылку - вы можете распоряжаться только самим объектом.

Вместо удаления b вы должны написать:

_capturedImage.Dispose();
_capturedImage = b;
2 голосов
/ 15 января 2010

_capturedImage и b являются ссылками на один и тот же базовый объект. Вызов b.Dispose (); также избавится от _capturedImage, так как они обе являются ссылками, которые указывают на один и тот же блок данных. Как только b выходит из области видимости (т.е. когда Invert возвращается), b прекращает существовать, но GC не будет собирать данные, поскольку _capturedImage по-прежнему указывает на него.

1 голос
/ 16 января 2010

Общее правило, когда вам нужно создать новый битовый массив для замены другого - сохранить ссылку на старый битовый массив, назначить новый для переменной, которую вы используете для его хранения, а затем утилизировать старый.

Таким образом, если у вас есть какое-либо поведение, связанное с модификацией переменной хранения, вы избегаете «мерцания». Это обычно используется в двойной буферизации;

public bool Invert() 
{
    //this will create a clone of _captureImage, so you effectivly have 2 Bitmaps at that point
    Bitmap b = new Bitmap(_capturedImage); 

    unsafe 
    {
     //random code not relevant.
    }

    var old = _capturedImage; //store old reference

    //assign, any events will seemlesly transition from the old to the new Bitmap
    _capturedImage = b; 
    old.Dispose(); //get rid of the old Bitmap

    return true;
}
0 голосов
/ 15 января 2010

Как уже упоминали другие, вы заставляете b и _capturedImage указывать на один и тот же объект, поэтому, когда вы утилизируете b, _capturedImage тоже ставится в тупик.

Я не вижу необходимости вызывать Dipose () Вот.Переменная объявляется в области действия функции, поэтому у нее не будет ссылок, и GC очистит ее автоматически.

На самом деле, я даже не вижу необходимости в переменной 'b'.Почему бы вам просто не использовать _capturedImage для всей функции и не усложнять ситуацию?

0 голосов
/ 15 января 2010

image.Clone ()

Вам придется снова привести результат к вашему типу данных, поскольку Clone () возвращает System.Object.

Редактировать: Должно быть, я неправильно понял проблему. Я думал, что вы хотите иметь изображение, которое не может быть уничтожено кодом в другом месте. Пока вы делитесь ссылками на одно и то же изображение в памяти, все остальные, кто знает об этом изображении, могут им распоряжаться, эффективно подставляя вас. Клонируя изображение, вы гарантируете, что никто другой (или какой-либо другой код, который вы написали) не сможет его утилизировать.

...