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


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

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

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

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

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

13 175

13 ответов:

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

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

порывшись в IDisposable

и

Понимание IDisposable

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

еще одна причина, чтобы избежать установки объектов в 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 обычно оптимизирует назначение до null, так что оба бита кода в конечном итоге являются тот же.

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

также:

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

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

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

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

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

скорее всего, ваш код не структурирован достаточно плотно, если вы чувствуете необходимость 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

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

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

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

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

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

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

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

отдельно от этого очень практически картина LazyLoad.

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

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

по моему опыту, это очень полезный трюк.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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