Есть ли смысл устанавливать obj = null (Nothing) в Dispose ()? - PullRequest
32 голосов
/ 17 февраля 2010

Есть ли смысл устанавливать пользовательский объект на null (Nothing в VB.NET) в методе Dispose()? Может ли это предотвратить утечки памяти или это бесполезно?!

Давайте рассмотрим два примера:

public class Foo : IDisposable
{
    private Bar bar; // standard custom .NET object

    public Foo(Bar bar) {
        this.bar = bar;
    }
    public void Dispose() {
        bar = null; // any sense?
    }
}

public class Foo : RichTextBox
{
    // this could be also: GDI+, TCP socket, SQl Connection, other "heavy" object
    private Bitmap backImage; 

    public Foo(Bitmap backImage) {
        this.backImage = backImage;
    }

    protected override void Dispose(bool disposing) {
        if (disposing) {
            backImage = null;  // any sense?
        }
    }
}

Ответы [ 8 ]

24 голосов
/ 17 февраля 2010

Лично я склонен; по двум причинам:

  • это означает, что, если кто-то забыл выпустить Foo (возможно, из события), любые нижестоящие объекты (в данном случае Bitmap) все еще можно собирать (в некоторый момент в будущем - всякий раз, когда GC чувствует, что нравится); вероятно , что это всего лишь мелкая оболочка вокруг неуправляемого ресурса, но каждая мелочь помогает.
    • Я на самом деле не любит, когда случайно висит целый граф объектов только потому, что пользователь забыл отцепить одно событие; IDisposable - это удобный переключатель "почти убить" - почему бы не отключить все доступное?
  • что еще более важно, теперь я могу дерзко использовать это поле, чтобы проверить (в методах и т. Д.) На удаление, выбрасывая ObjectDisposedException, если это null
20 голосов
/ 17 февраля 2010

Цель Dispose() - разрешить очистку ресурсов, которые не обрабатываются сборщиком мусора. Об объектах заботится GC, поэтому в действительности нет необходимости устанавливать ссылку на ноль при нормальных обстоятельствах.

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

4 голосов
/ 17 февраля 2010

Это почти бесполезно. Я полагаю, что установка NULL в старые дни COM / VB уменьшит ваш счетчик ссылок.

Это не так с .NET. Когда вы устанавливаете bar в null, вы ничего не разрушаете и не выпускаете. Вы просто меняете ссылку, на которую указывает панель, с вашего объекта на «ноль». Ваш объект все еще существует (хотя сейчас, так как к нему ничего не относится, он, в конечном счете, будет собирать мусор). За редкими исключениями, и в большинстве случаев это то же самое, что произошло бы, если бы вы просто не сделали Foo IDisposable во-первых.

Основная цель IDisposable - позволить вам высвобождать неуправляемых ресурсов, таких как сокеты TCP или соединения SQL, или что-либо еще. Обычно это делается путем вызова любой функции очистки, которую предоставляет неуправляемый ресурс, а не путем задания ссылки на «null».

1 голос
/ 18 февраля 2010

В VB.NET там имеет смысл установить Nothing объявлено Private WithEvents объектов.

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

1 голос
/ 17 февраля 2010

В C # установка объекта в null просто освобождает ссылку на объект.

Таким образом, теоретически лучше освободить ссылку на управляемые объекты в Dispose-Method в C #, но только для возможности GC собирать ссылочный объект до сбора удаленного объекта. Поскольку оба они, скорее всего, будут собраны в одном прогоне, GC наиболее вероятно распознает, что на объект, на который имеется ссылка, ссылается только удаленный тип, поэтому оба могут быть собраны.

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

1 голос
/ 17 февраля 2010

Это может иметь смысл, если вы хотите как-то предотвратить повторное использование имеющегося в распоряжении экземпляра.

Когда вы устанавливаете ссылки на одноразовые поля равными нулю, вы гарантированно больше не будете использовать экземпляры.

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

Это может не иметь смысла для вас, если все IDisposable объекты имеют свойство IsDisposed и / или выдают ObjectDisposedException, если они используются после их удаления - некоторые могут нарушить этот принцип и установить для них значение null может предотвратить возникновение нежелательных эффектов.

0 голосов
/ 17 апреля 2012

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

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

private void Reset()
{
    if(_dataset != null)
    {
       _dataset.Dispose();
       _dataset = null;
    }
    //..More such member variables like oracle connection etc. _oraConnection
 }
0 голосов
/ 17 февраля 2010

Цель dispose() - очистить неуправляемые ресурсы. Соединения TCP, соединения с базой данных и другие объекты базы данных, а также множество таких неуправляемых ресурсов должны быть освобождены разработчиком в методе dispose. Так что это действительно имеет смысл.

...