Вопрос:

Setting Objects to Null/Nothing after use in .NET

c# .net vb.net memory memory-management

79840 просмотра

14 ответа

18950 Репутация автора

Should you set all the objects to null (Nothing in VB.NET) once you have finished with them?

I understand that in .NET it is essential to dispose of any instances of objects that implement the IDisposable interface to release some resources although the object can still be something after it is disposed (hence the isDisposed property in forms), so I assume it can still reside in memory or at least in part?

I also know that when an object goes out of scope it is then marked for collection ready for the next pass of the garbage collector (although this may take time).

So with this in mind will setting it to null speed up the system releasing the memory as it does not have to work out that it is no longer in scope and are they any bad side effects?

MSDN articles never do this in examples and currently I do this as I cannot see the harm. However I have come across a mixture of opinions so any comments are useful.

Автор: John Источник Размещён: 05.08.2008 08:14

Ответы (14)


-1 плюса

34996 Репутация автора

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

Автор: GateKiller Размещён: 05.08.2008 08:21

15 плюса

17471 Репутация автора

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

Автор: Karl Seguin Размещён: 05.08.2008 08:23

5 плюса

68776 Репутация автора

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

Автор: Bob Размещён: 05.08.2008 08:32

7 плюса

5548 Репутация автора

Также:

using(SomeObject object = new SomeObject()) 
{
  // do stuff with the object
}
// the object will be disposed of
Автор: Steve Tranby Размещён: 05.08.2008 08:37

1 плюс

60466 Репутация автора

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

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

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

Автор: Patrick Размещён: 05.08.2008 08:46

68 плюса

98134 Репутация автора

Решение

Karl is absolutely correct, there is no need to set objects to null after use. If an object implements IDisposable, just make sure you call IDisposable.Dispose() when you're done with that object (wrapped in a try..finally, or, a using() block). But even if you don't remember to call Dispose(), the finaliser method on the object should be calling Dispose() for you.

I thought this was a good treatment:

Digging into IDisposable

and this

Understanding IDisposable

There isn't any point in trying to second guess the GC and its management strategies because it's self tuning and opaque. There was a good discussion about the inner workings with Jeffrey Richter on Dot Net Rocks here: Jeffrey Richter on the Windows Memory Model and Richters book CLR via C# chapter 20 has a great treatment:

Автор: Kev Размещён: 05.08.2008 08:56

7 плюса

7716 Репутация автора

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

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

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

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

Автор: dbkk Размещён: 09.08.2008 11:16

7 плюса

30163 Репутация автора

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

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

Автор: mbillard Размещён: 09.08.2008 12:13

35 плюса

20746 Репутация автора

Another reason to avoid setting objects to null when you are done with them is that it can actually keep them alive for longer.

e.g.

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

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

will allow the object referred by someType to be GC'd after the call to "DoSomething" but

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;
}

may sometimes keep the object alive until the end of the method. The JIT will usually optimized away the assignment to null, so both bits of code end up being the same.

Автор: Wilka Размещён: 15.08.2008 02:43

1 плюс

35251 Репутация автора

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

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

Автор: Scott Dorman Размещён: 17.08.2008 04:46

3 плюса

107 Репутация автора

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

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

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

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

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

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

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

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

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

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

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

Автор: KenF Размещён: 11.04.2012 01:12

5 плюса

739 Репутация автора

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

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

private void Reset()
{
    if(_dataset != null)
    {
       _dataset.Dispose();
       _dataset = null;
    }
    //..More such member variables like oracle connection etc. _oraConnection
 }
Автор: Munish Goyal Размещён: 17.04.2012 08:55

0 плюса

147 Репутация автора

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

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

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

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

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

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

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

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

Автор: John Размещён: 10.05.2016 01:07

0 плюса

130 Репутация автора

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

Говорит:

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

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

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

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

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

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

Blockquote

Заключение:

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

Автор: Ebleme Размещён: 27.03.2019 12:50
32x32