Сведения о вопросе

Henry

16:03, 1st July, 2020

Теги

c#   .net   vb.net   memory-management   null    

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

Просмотров: 527   Ответов: 14

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

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

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

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

MSDN статьи НИКОГДА не делают этого в примерах, и в настоящее время я делаю это так, как не могу видишь, какой вред. Однако я столкнулся со смешением мнений, поэтому любые комментарии полезны.



  Сведения об ответе

padenie

18:03, 1st July, 2020

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

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

Покопавшись в IDisposable

а это

Понимание IDisposable

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


  Сведения об ответе

VERSUION

18:03, 1st July, 2020

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


  Сведения об ответе

PHPH

18:03, 1st July, 2020

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


  Сведения об ответе

FAriza

18:03, 1st July, 2020

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

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

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

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


  Сведения об ответе

lool

18:03, 1st July, 2020

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

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


  Сведения об ответе

darknet

18:03, 1st July, 2020

Также:

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


  Сведения об ответе

SSESION

18:03, 1st July, 2020

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


  Сведения об ответе

screen

18:03, 1st July, 2020

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

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

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


  Сведения об ответе

PROGA

18:03, 1st July, 2020

этот вид "there is no need to set objects to null after use" не совсем точен. Есть моменты, когда вам нужно NULL переменную после ее удаления.

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

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

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

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

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

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

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

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

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

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


  Сведения об ответе

ITSME

18:03, 1st July, 2020

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

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


  Сведения об ответе

DINO

18:03, 1st July, 2020

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

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

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


  Сведения об ответе

lats

18:03, 1st July, 2020

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

Говорит:

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

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

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

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

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

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

Вывод:

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


  Сведения об ответе

appple

18:03, 1st July, 2020

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

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

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

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

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

Я действительно понимаю мышление "unnecessary things" (как пустые строки) "are nothing but noise and clutter up code.", которое было у меня раньше в моей карьере; я полностью понимаю это. В этот момент я склоняюсь к тому, что делает код более ясным. Это не значит, что я добавляю даже 50 строк "noise" в свои программы - это несколько строк здесь или там.

Есть исключения из любого правила. В сценариях с изменчивой памятью, статической памятью, условиями гонки, синглетами, использованием данных "stale" и всем этим видом гнили все по-другому: вы NEED управляете своей собственной памятью, блокируя и обнуляя ее, потому что память не является частью Вселенной GC-надеюсь, все это понимают. rest того времени с GC'd языками это вопрос стиля, а не необходимости или гарантированной производительности boost.

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


  Сведения об ответе

DO__IT

18:03, 1st July, 2020

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


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться