Установка объектов на Null/Nothing после использования в .NET.

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

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

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

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

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

Ответ 1

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

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

Копаться в IDisposable

и это

Понимание IDisposable

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

Ответ 2

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

например.

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

    // ... rest of method not using '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 обычно оптимизирует присвоение нулевому значению, поэтому оба бита кода оказываются одинаковыми.

Ответ 4

также:

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

Ответ 5

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

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

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

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

Ответ 6

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

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

Как упоминалось Steve Tranby

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

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

Ответ 8

В общем, нет необходимости устанавливать значение null. Но предположим, что у вас есть функциональность Reset в вашем классе.

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

private void Reset()
{
    if(_dataset != null)
    {
       _dataset.Dispose();
       _dataset = null;
    }
    //..More such member variables like oracle connection etc. _oraConnection
 }

Ответ 9

этот тип "нет необходимости устанавливать объекты в null после использования" не совсем точен. Иногда вам нужно NULL переменную после ее утилизации.

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

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

Скажем, у меня есть экземпляр ObjA class A. class A имеет общедоступное свойство PropB class B.

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

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

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

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

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

В конце концов, утерянное свойство будет опущено, но это не было детерминированным с моей точки зрения.

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

Ответ 10

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

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

В целом, вы действительно не должны беспокоиться. Пусть компилятор и GC выполняют свою работу, чтобы вы могли сделать свой.

Ответ 11

Взгляните на эту статью: http://www.codeproject.com/KB/cs/idisposable.aspx

По большей части установка объекта в значение null не влияет. Единственный раз, когда вы должны это сделать, - это работать с "большим объектом" размером более 84 КБ (например, растровыми изображениями).

Ответ 12

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

Говорит:

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

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

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

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

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

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

Заключение:

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

Ответ 13

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

Лично я часто явно устанавливаю переменные в null, когда я закончил с ними как форму самостоятельной документации. Я не объявляю, не использую, а затем устанавливаю значение null позже - я null сразу после того, как они больше не нужны. Я прямо говорю: "Я официально с тобой... ушел..."

Уничтожает необходимость на языке GC'd? Нет. Это полезно для GC? Возможно, да, может быть, нет, не знаю наверняка, по дизайну я действительно не могу это контролировать, и независимо от того, отвечают ли вы сегодня на эту версию или что, будущие реализации GC могут изменить ответ, который не поддается контролю. Плюс, если/когда обнуление оптимизировано, это немного больше, чем фантастический комментарий, если вы это сделаете.

Я полагаю, что если он сделает мое намерение более ясным для следующего бедного дурака, который следует по моим стопам, и если он "может" потенциально может помочь GC иногда, то он того стоит мне. В основном это заставляет меня чувствовать себя аккуратно и ясно, и Монго любит чувствовать себя аккуратно и ясно.:)

Я смотрю на это так: существуют языки программирования, позволяющие людям давать другим людям идею намерения, а компилятор - запрос на работу о том, что делать - компилятор преобразует этот запрос на другой язык (иногда несколько) для CPU - CPU могут дать вам понять, какой язык вы использовали, настройки вкладки, комментарии, стилистические акценты, имена переменных и т.д. - процессор все о битовом потоке, который сообщает ему, какие регистры и коды операций и места памяти крутить. Многие вещи, написанные в коде, не преобразуются в то, что потребляется ЦП в указанной нами последовательности. Наши C, С++, С#, Lisp, Babel, ассемблер или что-то другое - это теория, а не реальность, написанная как выражение о работе. То, что вы видите, не то, что вы получаете, да, даже на языке ассемблера.

Я понимаю, что мышление "ненужных вещей" (например, пустые строки) "не что иное, как шум и загромождение кода". Это был я раньше в моей карьере; Я полностью понимаю это. На этом этапе я склоняюсь к тому, что делает код более ясным. Это не похоже на то, что я добавляю еще 50 строк "шума" к моим программам - это несколько строк здесь или там.

Существуют исключения из любого правила. В сценариях с энергозависимой памятью, статичной памятью, условиями гонки, синглтонами, использованием "устаревших" данных и всего такого рода гнили, которые различны: вам нужно управлять собственной памятью, блокировать и обнулять по мере того, как память не является частью GC'd Universe - надеюсь, все это понимают. В остальное время с языками GC'd это вопрос стиля, а не необходимость или гарантированное повышение производительности.

В конце дня убедитесь, что вы понимаете, что подходит для GC, а что нет; блокировать, уничтожать и аннулировать надлежащим образом; воск, воск; вдох-выдох; и для всего остального я говорю: если он чувствует себя хорошо, сделайте это. Ваш пробег может варьироваться... как он должен...

Ответ 14

Некоторые объекты предполагают метод .dispose(), который заставляет ресурс удаляться из памяти.