Установка объектов в ноль / ничего после использования в .NET - PullRequest
178 голосов
/ 06 августа 2008

Должны ли вы установить для всех объектов значение null (Nothing в VB.NET), как только закончите с ними?

Я понимаю, что в .NET важно избавиться от любых экземпляров объектов, которые реализуют интерфейс IDisposable, чтобы высвободить некоторые ресурсы, хотя объект может все еще быть чем-то после его удаления (следовательно, свойство isDisposed в формах ), поэтому я предполагаю, что он все еще может находиться в памяти или хотя бы частично?

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

Итак, учитывая это, установит ли он значение null, чтобы ускорить высвобождение памяти системой, поскольку ей не нужно выяснять, что она больше не находится в области видимости и являются ли они плохими побочными эффектами?

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

Ответы [ 14 ]

68 голосов
/ 06 августа 2008

Карл абсолютно прав, нет необходимости устанавливать объекты в null после использования. Если объект реализует IDisposable, просто убедитесь, что вы вызываете IDisposable.Dispose(), когда закончите работу с этим объектом (завернутый в блок try .. finally или using()). Но даже если вы не помните, чтобы вызывать Dispose(), метод finaliser для объекта должен вызывать Dispose() для вас.

Я думал, что это хорошее лечение:

Копание в IDisposable

и это

Понимание IDisposable

Нет никакого смысла пытаться угадать GC и его стратегии управления, потому что он самонастраивается и непрозрачен. Здесь было хорошее обсуждение внутренней работы с Джеффри Рихтером на Dot Net Rocks: Джеффри Рихтер на модели памяти Windows и Книга Рихтерса CLR через C # глава 20 имеет отличную трактовку:

35 голосов
/ 15 августа 2008

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

, например

void foo()
{
    var someType = new SomeType();
    someType.DoSomething();
    // someType is now eligible for garbage collection         

    // ... rest of method not using 'someType' ...
}

позволит объекту, указанному someType, быть GC'd после вызова «DoSomething», но

void foo()
{
    var someType = new SomeType();
    someType.DoSomething();
    // someType is NOT eligible for garbage collection yet
    // because that variable is used at the end of the method         

    // ... rest of method not using 'someType' ...
    someType = null;
}

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

14 голосов
/ 06 августа 2008

Нет, не обнулять объекты. Вы можете проверить http://codebetter.com/blogs/karlseguin/archive/2008/04/27/foundations-of-programming-pt-7-back-to-basics-memory.aspx для получения дополнительной информации, но установка нулевого значения ничего не изменит, кроме как испачкать ваш код.

7 голосов
/ 09 августа 2008

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

Существует несколько способов ограничить область действия переменной:

Как уже упоминалось Стив Транби

using(SomeObject object = new SomeObject()) 
{
  // do stuff with the object
}
// the object will be disposed of

Аналогично, вы можете просто использовать фигурные скобки:

{
    // Declare the variable and use it
    SomeObject object = new SomeObject()
}
// The variable is no longer available

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

7 голосов
/ 09 августа 2008

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

Если объект реализует IDisposable и хранится в поле, я думаю, это хорошо, чтобы обнулить его, просто чтобы избежать использования удаленного объекта. Ошибки следующего вида могут быть болезненными:

this.myField.Dispose();
// ... at some later time
this.myField.DoSomething();

Хорошо обнулить поле после его удаления и получить NullPtrEx прямо в строке, где поле используется снова. В противном случае вы можете столкнуться с какой-то загадочной ошибкой (в зависимости от того, что именно делает DoSomething).

7 голосов
/ 06 августа 2008

Также:

using(SomeObject object = new SomeObject()) 
{
  // do stuff with the object
}
// the object will be disposed of
5 голосов
/ 17 апреля 2012

Как правило, нет необходимости устанавливать в ноль. Но предположим, у вас есть функция сброса в вашем классе.

Тогда вы можете это сделать, потому что вы не хотите вызывать dispose дважды, поскольку некоторые из Dispose могут быть реализованы неправильно и вызывают исключение System.ObjectDisposed.

private void Reset()
{
    if(_dataset != null)
    {
       _dataset.Dispose();
       _dataset = null;
    }
    //..More such member variables like oracle connection etc. _oraConnection
 }
5 голосов
/ 06 августа 2008

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

3 голосов
/ 11 апреля 2012

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

Да, вы ВСЕГДА должны звонить .Dispose() или .Close() на все, что у вас есть, когда вы закончите. Будь то файловые дескрипторы, соединения с базой данных или одноразовые объекты.

Отдельно от этого стоит очень практичный шаблон LazyLoad.

Скажем, у меня есть и создан ObjA из class A. Class A имеет публичную собственность под названием PropB из class B.

Внутренне, PropB использует закрытую переменную _B и по умолчанию имеет значение null. Когда используется PropB.Get(), он проверяет, является ли _PropB нулевым, и, если это так, открывает ресурсы, необходимые для создания экземпляра B в _PropB. Затем возвращается _PropB.

По моему опыту, это действительно полезный трюк.

Когда возникает необходимость обнуления, если вы сбрасываете или изменяете A каким-либо образом, чтобы содержимое _PropB было дочерним по отношению к предыдущим значениям A, вам нужно будет удалить и сбросить нуль _PropB поэтому LazyLoad может сбросить для получения правильного значения, если код требует этого.

Если вы только выполните _PropB.Dispose() и вскоре после этого ожидаете, что проверка LazyLoad на ноль будет успешной, она не будет нулевой, и вы будете просматривать устаревшие данные. По сути, вы должны обнулить его после Dispose(), просто чтобы быть уверенным.

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

В конце концов, свойство disposed исчезнет, ​​но, с моей точки зрения, это недетерминировано.

Основная причина, как указывает dbkk, заключается в том, что родительский контейнер (ObjA с PropB) сохраняет экземпляр _PropB в области видимости, несмотря на Dispose().

1 голос
/ 27 марта 2019

Стивен Клири очень хорошо объясняет в этом посте: Должен ли я установить для переменных значение Null, чтобы помочь в сборке мусора?

Говорит:

Краткий ответ для нетерпеливых Да, если переменная является статическим полем, или если вы пишете перечислимый метод (с помощью yield return) или асинхронный метод (с использованием async и await). В противном случае, нет.

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

(Даже если вы реализуете IDisposable.Dispose, вам все равно не следует устанавливать переменные в null).

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

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

Установка статических полей на ноль не имеет смысла, если весь процесс завершается. В этот момент собирается куча мусора, включая все корневые объекты.

Вывод:

Статические поля ; это об этом. Все остальное - трата времени .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...