Должны ли вы установить все объекты в null
(Nothing
в VB.NET), как только вы закончите с ними?
Я понимаю, что в .NET важно избавиться от любых экземпляров объектов, которые реализуют интерфейс IDisposable
, чтобы освободить некоторые ресурсы, хотя объект все равно может быть чем-то после его размещения (следовательно, свойство isDisposed
в формах), поэтому я предполагаю, что он все еще может находиться в памяти или хотя бы частично?
Я также знаю, что когда объект выходит из области видимости, он затем помечен для коллекции, готовой для следующего прохода сборщика мусора (хотя это может занять время).
Итак, имея в виду, он установит его на null
, ускорит выпуск системы, освобождая память, так как ей не нужно работать, что она больше не находится в области видимости и являются ли они плохими побочными эффектами?
Статьи MSDN никогда не делают этого в примерах, и в настоящее время я делаю это, поскольку я не могу видеть вред. Однако я встретил смесь мнений, поэтому любые комментарии полезны.
Карл абсолютно прав, нет необходимости устанавливать объекты null после использования. Если объект реализует IDisposable
, просто убедитесь, что вы вызываете IDisposable.Dispose()
, когда вы закончите с этим объектом (завернутый в блок try
.. finally
, или using()
). Но даже если вы не забыли называть Dispose()
, метод finaliser для объекта должен вызывать Dispose()
для вас.
Я подумал, что это хорошее лечение:
и этот
Нет смысла пытаться догадаться о GC и ее стратегиях управления, потому что она самонастраивается и непрозрачна. Было хорошее обсуждение внутренней работы с Джеффри Рихтером на Dot Net Rocks: Джеффри Рихтер в модели памяти Windows и Книга Рихтера CLR через С# главу 20 имеет отличное лечение:
Еще одна причина, по которой вы не устанавливаете объекты в 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 обычно оптимизирует присвоение нулевому значению, поэтому оба бита кода оказываются одинаковыми.
GC.KeepAlive(someType);
См. Ericlippert.com/2013/06/10/construction-destruction
Нет нулевых объектов. Вы можете проверить http://codebetter.com/blogs/karlseguin/archive/2008/04/27/foundations-of-programming-pt-7-back-to-basics-memory.aspx для получения дополнительной информации, но установление нулевого значения ничего не сделает, кроме грязного кода.
В общем, нет необходимости нулевых объектов после использования, но в некоторых случаях я считаю это хорошей практикой.
Если объект реализует IDisposable и хранится в поле, я думаю, что это полезно для его нулевого значения, чтобы избежать использования объекта. Ошибки следующего вида могут быть болезненными:
this.myField.Dispose();
// ... at some later time
this.myField.DoSomething();
Хорошо удалить поле после его удаления и получить NullPtrEx прямо в строке, где поле используется снова. В противном случае вы можете столкнуться с некоторой загадочной ошибкой по строке (в зависимости от того, что делает DoSomething).
.Dispose()
. Если вы найдете его, вы не используете IDisposable правильно. Единственное использование для одноразового предмета должно быть в пределах блока использования. А после использования блока у вас даже нет доступа к myField
. А в блоке using установка в null
не обязательна, блок using избавится от объекта за вас.
также:
using(SomeObject object = new SomeObject())
{
// do stuff with the object
}
// the object will be disposed of
Скорее всего, ваш код недостаточно структурирован, если вы чувствуете потребность в переменных 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
Я нахожу, что использование фигурных скобок без каких-либо "заголовков", чтобы действительно очистить код и помочь сделать его более понятным.
В общем, нет необходимости устанавливать значение 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
}
Единственный раз, когда вы должны установить переменную в значение null, - это когда переменная не выходит за пределы области действия, и вам больше не нужны данные, связанные с ней. В противном случае нет необходимости.
этот тип "нет необходимости устанавливать объекты в 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()
.
Взгляните на эту статью: http://www.codeproject.com/KB/cs/idisposable.aspx
По большей части установка объекта в значение null не влияет. Единственный раз, когда вы должны это сделать, - это работать с "большим объектом" размером более 84 КБ (например, растровыми изображениями).
Есть некоторые случаи, когда имеет смысл нулевые ссылки. Например, когда вы пишете коллекцию - как очередь приоритетов - и по вашему контракту, вы не должны сохранять эти объекты живыми для клиента после того, как клиент удалил их из очереди.
Но такого рода вещи имеют значение только в долговечных коллекциях. Если очередь не выживет в конце функции, в которой она была создана, тогда это имеет значение намного меньше.
В целом, вы действительно не должны беспокоиться. Пусть компилятор и GC выполняют свою работу, чтобы вы могли сделать свой.
Я считаю, что по дизайну разработчиков GC вы не можете ускорить GC с аннулированием. Я уверен, что они предпочтут, чтобы вы не беспокоились о том, как/когда GC запускается - рассматривайте его как это вездесущее Быть защищая и наблюдая за и для вас... (наклоняет голову вниз, поднимает кулак к небу)...
Лично я часто явно устанавливаю переменные в null, когда я закончил с ними как форму самостоятельной документации. Я не объявляю, не использую, а затем устанавливаю значение null позже - я null сразу после того, как они больше не нужны. Я прямо говорю: "Я официально с тобой... ушел..."
Уничтожает необходимость на языке GC'd? Нет. Это полезно для GC? Возможно, да, может быть, нет, не знаю наверняка, по дизайну я действительно не могу это контролировать, и независимо от того, отвечают ли вы сегодня на эту версию или что, будущие реализации GC могут изменить ответ, который не поддается контролю. Плюс, если/когда обнуление оптимизировано, это немного больше, чем фантастический комментарий, если вы это сделаете.
Я полагаю, что если он сделает мое намерение более ясным для следующего бедного дурака, который следует по моим стопам, и если он "может" потенциально может помочь GC иногда, то он того стоит мне. В основном это заставляет меня чувствовать себя аккуратно и ясно, и Монго любит чувствовать себя аккуратно и ясно.:)
Я смотрю на это так: существуют языки программирования, позволяющие людям давать другим людям идею намерения, а компилятор - запрос на работу о том, что делать - компилятор преобразует этот запрос на другой язык (иногда несколько) для CPU - CPU могут дать вам понять, какой язык вы использовали, настройки вкладки, комментарии, стилистические акценты, имена переменных и т.д. - процессор все о битовом потоке, который сообщает ему, какие регистры и коды операций и места памяти крутить. Многие вещи, написанные в коде, не преобразуются в то, что потребляется ЦП в указанной нами последовательности. Наши C, С++, С#, Lisp, Babel, ассемблер или что-то другое - это теория, а не реальность, написанная как выражение о работе. То, что вы видите, не то, что вы получаете, да, даже на языке ассемблера.
Я понимаю, что мышление "ненужных вещей" (например, пустые строки) "не что иное, как шум и загромождение кода". Это был я раньше в моей карьере; Я полностью понимаю это. На этом этапе я склоняюсь к тому, что делает код более ясным. Это не похоже на то, что я добавляю еще 50 строк "шума" к моим программам - это несколько строк здесь или там.
Существуют исключения из любого правила. В сценариях с энергозависимой памятью, статичной памятью, условиями гонки, синглтонами, использованием "устаревших" данных и всего такого рода гнили, которые различны: вам нужно управлять собственной памятью, блокировать и обнулять по мере того, как память не является частью GC'd Universe - надеюсь, все это понимают. В остальное время с языками GC'd это вопрос стиля, а не необходимость или гарантированное повышение производительности.
В конце дня убедитесь, что вы понимаете, что подходит для GC, а что нет; блокировать, уничтожать и аннулировать надлежащим образом; воск, воск; вдох-выдох; и для всего остального я говорю: если он чувствует себя хорошо, сделайте это. Ваш пробег может варьироваться... как он должен...
Некоторые объекты предполагают метод .dispose()
, который заставляет ресурс удаляться из памяти.