2010-10-15 4 views
4

В моем WPF-приложения, я называю новые окна следующим образом:памяти оптимизации кода Потребляемая, теория сборщик мусора

_newWin = new WinWorkers_AddWorker(); 
_newWin.WindowState = this.WindowState; 
_newWin.Show(); 

Где _newWin является private Window object.

Мой вопрос: должен ли я назначить нулевое значение _newWin после того, как позвоню _newWin.Show()?

Будет ли это уменьшать потребление памяти, поскольку сборщик мусора/деструктор очистят объекты с нулевым значением раньше?

Спасибо.

ответ

6

Обычно не имеет значения для установки значения null. Это очень редко полезно. Это иногда вредно.

Рассмотрим сначала простейший случай:

private void DoStuff() 
{ 
    var newWin = new WinWorkers_AddWorker(); 
    newWin.WindowState = this.WindowState; 
    newWin.Show(); 
    int irrelevant = 42; 
    this.whoCares = irrelevant * 7; 
    int notRelevantEither = irrelevant + 1; 
    this.stillDontCare = notRelevantEither * irrelevant; 
} 

newWin Здесь существует только в этом методе; он создается в нем и не выходит из области действия метода, возвращая или назначая его члену с более широкой областью.

Спросите у многих людей, когда newWin получает сбор мусора, и они скажут вам, что это произойдет после строки с this.stillDontCare, потому что тогда newWin выходит за рамки. Таким образом, мы могли бы немного выиграть, назначив newWin = null сразу после его последнего использования, но, вероятно, незначительно.

Концептуально это правда, потому что мы можем добавить код, который имеет дело с newWin в любом месте до этой точки, и newWin есть для нас, чтобы использовать.

На самом деле, вполне вероятно, что newWin будет иметь право на сбор сразу после .Show(). Хотя после этого он концептуально находится в области видимости, он фактически не используется, и компилятор это знает. (Теперь с помощью «компилятора» я буду понимать весь процесс, который создает фактический текущий код, объединяющий компилятор IL и дрожание).Поскольку память, используемая самим newWin (то есть ссылка на стек, а не объект) больше не используется, компилятор может использовать эту память для irrelevant или что-то еще. Там, где нет ссылки на живые ссылки, объект имеет право на сбор.

Действительно, если последние несколько методов, вызываемых объектом, фактически не используют указатель this (будь то напрямую или с помощью полей-членов), тогда объект может быть собран даже до того, как эти методы будут вызваны, поскольку они не фактически использовать объект. Если у вас был метод, указатель this никогда не использовался (опять же, прямо или косвенно), то он никогда не может быть создан!

Теперь, имея в виду, мы можем видеть, что на самом деле не произойдет даже незначительной незначительной разницы, которая, по-видимому, возникла бы, если бы мы должны были присвоить значение null переменной до того, как переменная выпадет из объем.

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

До сих пор так просто; хорошие вещи случаются, если мы оставляем себя в одиночестве, и оставаться в одиночестве легко.

Однако возможно, чтобы ссылка использовала значение null. Рассмотрим:

public class SomeClass 
{ 
    private WorkerThing _newWin; 
    private void DoStuff() 
    { 
    _newWin = new WinWorkers_AddWorker(); 
    _newWin.WindowState = this.WindowState; 
    _newWin.Show(); 
    } 
} 

Рассмотрим здесь, что на этот раз после того, как DoStuff() называется, _newWin хранится в переменной-члена. Он не будет выпадать из области действия до тех пор, пока не исчезнет экземпляр SomeClass. Когда это произойдет?

Ну, я не могу ответить на этот вопрос, но иногда ответ важен. Если и сам SomeClass тоже недолговечен, то кого это волнует. Он скоро выпадет из сферы, взяв с собой _newWin. Если, однако, мы назначили _newWin = null, тогда объект сразу будет иметь право на сбор.

Теперь некоторые важные оговорки к этому:

  1. В первую очередь, нет никаких оснований для _newWin быть переменной-члена. Если приведенный выше пример был полным кодом, мы бы переместили его обратно в локальный на DoStuff() и получили бы не только этот эффективный способ, но и , что гораздо важнее в наших шансах на правильность, поскольку мы не можем сделать что-то глупое до _newWin от другого участника.
  2. Если мы держимся за что-то в переменной-члене, это, вероятно, по уважительной причине. Эта веская причина перестанет быть фанатичной по поводу очистки переменных как можно быстрее.
  3. Большинство объектов просто не занимают столько памяти сами по себе. Членская переменная здесь или там не повредит.

Из-за этого основной причиной присвоения значения null переменной-члену является просто потому, что значение null стало наиболее подходящим. Назначение нулевого элемента, который больше не будет использоваться, как правило, не освобождает память ASAP, а потому, что он больше не подходит для использования, и это становится невозможным - и четко сигнализируется остальной части вашего кода как такового - когда он нулевой.

Если ссылка была более жил, чем метод (и, следовательно, положить в переменной-члена) и значительно короче долгоживущий, чем содержащего объект и потребленный очень большой объем памяти, то это просто о возможном что назначение нуля начнет иметь смысл. В крайне редких случаях, когда эта комбинация происходит, мы, вероятно, хотим присвоить ей значение null, чтобы указать, что ее больше нет для класса, так что мы по-прежнему не будем назначать нуль с целью освобождения это в GC. Это просто возможно, но на самом деле «нах».

0

Он не удалит объект, потому что он будет ссылаться в другом месте приложения (во внутреннем коде). В противном случае установка значения _newWin в значение null и получение собранного мусора заставит ваше окно исчезнуть (и, вероятно, программы), чего не бывает.

2

Сбор мусора не очищает объекты null. Если вы установили ссылку на null, вы просто удалите ссылку, указывающую на объект, чтобы вы фактически снизили счетчик сохранения.

Но этот счетчик будет уменьшен также, когда объект выходит из сферы действия без возможности вернуть обратно код. Так что вы пытаетесь сделать это бесполезно.

ГХ будет выбирать в любом случае, чтобы освободить его только тогда, когда на него не ссылаются больше, но если вы покажете, что окно, вы будете уверены, что где-то есть ссылка в любом случае ..

EDIT: как указано в комментарий, возможно, подсчет ссылок не так, как это делает .NET vm (извините, но я не использую платформу M $), но принцип остается тем же. Ваше окно не будет GCed, так как оно видно.

+1

Примечание подсчет не является реальным способом его сбора. Afaik это марка & развертки или аналогичные. – Dykam

+0

@ Dykam правильный, и это знак и развертка. В этом отношении он может быть собран до того, как он выпадет из сферы действия. Добавить подробный ответ. –

+0

Моно также не считается ссылкой. –

Смежные вопросы