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

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

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

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

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

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

5.08.2008 20:14:10
+1 отличный вопрос. Кто-нибудь знает обстоятельства, при которых компилятор полностью оптимизирует назначение? то есть кто-нибудь смотрел на MSIL при других обстоятельствах и отмечал IL для установки объекта на ноль (или его отсутствие).
Tim Medora 27.09.2010 07:43:55
15 ОТВЕТОВ
РЕШЕНИЕ

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

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

Копаться в IDisposable

и это

Понимание IDisposable

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

73
28.11.2018 12:51:42
Правило о том, что не следует устанавливать значение NULL, не является «жестким и быстрым» ... если объект помещается в кучу больших объектов (размер> 85 КБ), это поможет ГХ, если вы установите для объекта значение NULL, когда вы закончите. используй это.
Scott Dorman 1.11.2008 03:46:16
Я согласен в ограниченной степени, но если вы не начинаете испытывать нехватку памяти, я не вижу необходимости «преждевременной оптимизации», устанавливая нулевые объекты после использования.
Kev 1.11.2008 20:14:36
Весь этот бизнес «не преждевременно оптимизировать» звучит больше как «Предпочитаю медленный и не беспокойтесь, потому что процессоры становятся быстрее, а приложения CRUD в любом случае не нуждаются в скорости». Это может быть только я, хотя. :)
BobbyShaftoe 20.12.2008 04:42:09
На самом деле это означает: «Сборщик мусора лучше управляет памятью, чем вы». Это может быть только я, хотя. :)
BobRodes 7.06.2012 19:41:44
@BobbyShaftoe: Вероятно, так же неправильно говорить, что «преждевременная оптимизация - это плохо, всегда», так как это означает переход к противоположной крайности «звучит больше как« предпочитайте медленный »». Ни один разумный программист не скажет. Речь идет о нюансах и умном подходе к оптимизации. Лично я бы беспокоился о ясности кода и ЭТОЙ АКТУАЛЬНО ТЕСТИРОВАНИИ, поскольку лично я видел, как многие люди (в том числе и я, когда я был моложе) тратят слишком много времени на создание «идеального» алгоритма, только чтобы сэкономить 0,1 мс в 100 000 итераций все, пока читаемость была полностью снята.
Brent Rittenhouse 3.08.2017 17:10:28

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

-1
7.08.2017 20:52:26
Нет, это не так; Dispose () не собирает объект - он используется для выполнения детерминированной очистки, обычно освобождая неуправляемые ресурсы.
Marc Gravell♦ 2.11.2008 11:08:01
Учитывая, что детерминизм относится только к управляемым ресурсам, а не к неуправляемым (т.
nicodemus13 5.04.2011 17:05:49

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

14
5.08.2008 20:28:55
Приятное и подробное объяснение памяти в общей ссылке
user2323308 8.08.2014 12:11:50
Ссылка не работает. Без связанного контента этот ответ скорее бесполезен и должен быть удален.
Imre Pühvel 27.03.2019 08:07:39

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

5
5.08.2008 20:32:48
Это правда, но это также означает, что вы, вероятно, должны провести рефакторинг своего кода. Я не думаю, что мне когда-либо нужно было объявлять переменную вне ее предполагаемой области видимости.
Karl Seguin 5.08.2008 20:36:31
Если понимать, что «переменная» включает в себя поля объекта, тогда этот ответ имеет большой смысл. В случае, когда «переменная» означает только «локальная переменная» (метода), тогда мы, вероятно, говорим здесь о нишевых случаях (например, метод, который выполняется намного дольше, чем обычно).
stakx - no longer contributing 28.05.2017 12:21:42

Также:

using(SomeObject object = new SomeObject()) 
{
  // do stuff with the object
}
// the object will be disposed of
7
5.08.2008 20:37:30

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

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

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

1
5.08.2008 20:46:08

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

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

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

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

7
9.08.2008 11:16:04
Хорошо, удаленный объект должен вызвать исключение ObjectDisposedException, если он уже был удален. Насколько мне известно, для этого требуется повсеместный шаблонный код, но опять же, Disposed в любом случае является плохо продуманной парадигмой.
nicodemus13 5.04.2011 17:01:34
Ctrl + F для .Dispose(). Если вы найдете его, вы не используете IDisposable правильно. Единственное использование для одноразового предмета должно быть в пределах блока использования. А после использования блока у вас даже нет доступа к нему myField. А в блоке using установка значения nullне обязательна, блок using выберет объект для вас.
Suamere 11.01.2016 16:54:17

Скорее всего, ваш код недостаточно структурирован, если вам нужны 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
9.08.2008 12:13:12
Однажды я попытался использовать пользовательские локальные области видимости (в основном это смартта $$). Компания взорвалась.
Suamere 11.01.2016 16:56:20
Еще одно замечание: это потому, что компилятор c # найдет переменные локальной области, которые реализуют IDisposable, и вызовет .Dispose (MOST Of the time), когда их область действия закончится. Однако ... SQL-соединения - это одно большое время, когда .Dispose () никогда не оптимизируется. Есть некоторые типы, которые требуют явного внимания, поэтому я лично всегда делаю вещи явно, чтобы меня не укусили.
Suamere 11.01.2016 16:58:00

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

36
15.08.2008 14:43:34
Это интересный момент. Я всегда думал, что объекты не выходят за рамки, пока не завершится метод, в котором они определены. Если, конечно, объект находится в пределах блока Using или явно имеет значение Nothing или null.
Guru Josh 6.05.2014 16:15:38
Предпочтительный способ гарантировать, что они останутся в живых, это использовать. GC.KeepAlive(someType); См. Ericlippert.com/2013/06/10/construction-destruction
NotMe 10.07.2014 15:34:45

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

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

1
1.11.2008 03:47:17

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

Да, вы должны ВСЕГДА звонить .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, чтобы исключить нулевое значение, чтобы LazyLoad мог сбросить для получения правильного значения, ЕСЛИ код требует этого.

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

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

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

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

3
9.06.2012 16:56:16
Хороший пример, показывающий, как установка нуля вручную означает более фатальную ошибку для вызывающей стороны, и это хорошо.
rolls 17.07.2017 13:16:33

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

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

private void Reset()
{
    if(_dataset != null)
    {
       _dataset.Dispose();
       _dataset = null;
    }
    //..More such member variables like oracle connection etc. _oraConnection
 }
5
17.04.2012 08:55:49
Лучше всего просто отслеживать это с отдельным флагом, может быть.
Thulani Chivandikwa 13.09.2019 09:49:47

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

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

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

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

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

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

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

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

0
10.05.2016 13:07:53

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

Говорит:

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

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

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

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

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

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

Заключение:

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

1
23.04.2019 21:43:24

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

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

0
13.09.2019 09:52:55