Вопрос

DataSet и DataTable оба реализуют IDisposable , поэтому, согласно общепринятым рекомендациям, я должен вызывать их методы Dispose().

Однако, судя по тому, что я прочитал до сих пор, DataSet и DataTable на самом деле не имеют каких-либо неуправляемых ресурсов, поэтому Dispose() на самом деле мало что делает.

Кроме того, я не могу просто использовать using(DataSet myDataSet...) потому что DataSet содержит коллекцию таблиц данных.

Итак, на всякий случай мне нужно было бы выполнить итерацию через myDataSet.Таблицы, удалите каждую из таблиц данных, затем удалите DataSet.

Итак, стоит ли беспокоиться о вызове Dispose() для всех моих наборов данных и таблиц данных?

Добавление:

Для тех из вас, кто считает, что этот набор данных следует утилизировать:В общем, схема утилизации заключается в использовании using или try..finally, потому что вы хотите гарантировать, что Dispose() будет вызван.

Однако для коллекции это становится очень быстро некрасивым.Например, что вы делаете, если один из вызовов Dispose() выдал исключение?Проглатываете ли вы это (что "плохо"), чтобы продолжить утилизацию следующего элемента?

Или вы предлагаете мне просто вызвать myDataSet.Dispose() и забыть об удалении таблиц данных в myDataSet.Таблицы?

Это было полезно?

Решение

Вот пара обсуждений, объясняющих, почему Dispose не является необходимым для набора данных.

Распоряжаться или не распоряжаться ?:

Метод Dispose в DataSet существует ТОЛЬКО из-за побочного эффекта наследования - другими словами, на самом деле он не делает ничего полезного при доработке.

Следует ли вызывать Dispose для объектов DataTable и DataSet? включает в себя некоторые пояснения от MVP:

Пространство имен system.data (ADONET) не содержит неуправляемых ресурсов.Поэтому нет необходимости избавляться от любого из них, пока до тех пор, пока вы сами не добавили к нему что-то особенное.

Понимание метода Dispose и наборов данных? имеет a с комментарием от авторитета Скотта Аллена:

В практике мы редко размещаем набор данных, потому что это дает мало пользы "

Итак, существует консенсус в том, что в настоящее время нет веской причины вызывать Dispose для набора данных.

Другие советы

Обновление (1 декабря 2009):

Я хотел бы внести поправки в этот ответ и признать, что первоначальный ответ был ошибочным.

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

Однако оказывается, что DataSets, DataViews, DataTables подавлять доработку в своих конструкторах – вот почему вызов Dispose() для них явно ничего не делает.

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

(Это .СЕТЕВЫЕ авторы позаботились бы о том, чтобы подавить финализацию для тех самых типов, которые обычно занимают больше всего памяти, говорит о важности этой практики в целом для финализуемых типов.)

Несмотря на то, что эти детали все еще недостаточно документированы с момента создания .NET Framework (почти 8 лет назад), довольно удивительно (то, что вы, по сути, предоставлены сами себе, чтобы просеивать хотя и противоречивый, неоднозначный материал, чтобы собрать кусочки воедино, временами разочаровывает, но обеспечивает более полное понимание фреймворка, на который мы полагаемся каждый день).

После долгого чтения, вот мое понимание:

Если объект требует доработки, он мог бы занимают память дольше, чем это необходимо – вот почему:a) Любой тип, который определяет деструктор (или наследуется от типа, который определяет деструктор), считается завершаемым;б) При выделении (перед запуском конструктора) указатель помещается в очередь завершения;c) Завершаемый объект обычно требует 2 коллекции подлежит возврату (вместо стандартного 1);d) Подавление завершения не удаляет объект из очереди завершения (как сообщает !FinalizeQueue в SOS) Эта команда вводит в заблуждение;Знание того, какие объекты находятся в очереди завершения (само по себе), не помогает;Было бы полезно знать, какие объекты находятся в очереди завершения и все еще требуют завершения (есть ли команда для этого?)

Подавление завершения немного отключает заголовок объекта, указывающий среде выполнения, что ей не нужно вызывать свой финализатор (не нужно перемещать доступную очередь).;Он остается в очереди на завершение (и продолжает получать сообщения от !FinalizeQueue в SOS)

Классы DataTable, DataSet, DataView имеют корни в MarshalByValueComponent , завершаемом объекте, который может (потенциально) обрабатывать неуправляемые ресурсы

  • Поскольку DataTable, DataSet, DataView не вводят неуправляемые ресурсы, они подавляют доработку в своих конструкторах
  • Хотя это необычный шаблон, он освобождает вызывающего от необходимости беспокоиться о вызове Dispose после использования
  • Это, а также тот факт, что таблицы данных потенциально могут совместно использоваться в разных наборах данных, вероятно, является причиной того, что DataSets не хотят удалять дочерние таблицы данных
  • Это также означает, что эти объекты появятся под !FinalizeQueue в SOS
  • Однако эти объекты все равно должны быть восстановлены после одной коллекции, как и их не завершаемые аналоги

4 (новые ссылки):

Оригинальный Ответ:

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

Без сомнения, Утилизируйте должно быть вызывается для любых завершаемых объектов.

Таблицы данных являются Завершаемо.

Вызывающий Dispose значительно ускоряет восстановление памяти.

Маршалловый ценностный компонент звонки GC.SuppressFinalize(это) в его Dispose() - пропуск этого означает необходимость ждать десятки, если не сотни коллекций Gen0, прежде чем память будет освобождена:

С этим базовым пониманием финализации мы уже можем сделать некоторые очень важные выводы вещи:

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

Во-вторых, объекты, которые нуждаются в доработке наносят сопутствующий ущерб.Поскольку внутренние указатели на объект должны оставаться действительными, в памяти останутся не только объекты, непосредственно нуждающиеся в доработке , но и все, на что объект ссылается, прямо или косвенно, также останется в памяти.Если бы огромное дерево объектов было привязано к одному объекту, который требовал завершения, тогда все дерево задержалось бы, возможно, на долгое время, как мы только что обсуждали.Это поэтому важно использовать финализаторы экономно и размещать их на объектах которые имеют как можно меньше внутренних объектов указателей, насколько это возможно.В дереве пример, который я только что привел, вы можете легко избежать проблемы, переместив ресурсы, нуждающиеся в доработке, в отдельный объект и сохранив ссылку на этот объект в корне дерева.С этим скромным изменением сохранится только один объект (надеюсь, приятный небольшой объект) и затраты на доработку сведены к минимуму.

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

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

Ссылки:

1 - http://msdn.microsoft.com/en-us/library/ms973837.aspx

2 - http://vineetgupta.spaces.live.com/blog/cns !8DE4BDC896BEE1AD!1104.запись http://www.dotnetfunda.com/articles/article524-net-best-practice-no-2-improve-garbage-collector-performance-using-finalizedispose-pattern.aspx

3 - http://codeidol.com/csharp/net-framework/Inside-the-CLR/Automatic-Memory-Management/

Вы должны предположить , что он делает что - то полезное , и вызвать Dispose , даже если он ничего не делает в current .Воплощения NET Framework, нет никакой гарантии, что так и останется в будущих версиях, что приведет к неэффективному использованию ресурсов.

Даже если у объекта нет неуправляемых ресурсов, удаление может помочь GC, нарушив графики объектов.В общем случае, если object реализует IDisposable, то следует вызвать Dispose() .

Действительно ли Dispose() что-то делает или нет, зависит от данного класса.В случае DataSet реализация Dispose() наследуется от MarshalByValueComponent.Он удаляет себя из контейнера и вызывает удаленное событие.Исходный код приведен ниже (дизассемблирован с помощью .NET Reflector):

protected virtual void Dispose(bool disposing)
{
    if (disposing)
    {
        lock (this)
        {
            if ((this.site != null) && (this.site.Container != null))
            {
                this.site.Container.Remove(this);
            }
            if (this.events != null)
            {
                EventHandler handler = (EventHandler) this.events[EventDisposed];
                if (handler != null)
                {
                    handler(this, EventArgs.Empty);
                }
            }
        }
    }
}

Вы сами создаете таблицы данных?Потому что перебор дочерних элементов любого объекта (как в DataSet.Таблицы) обычно не требуется, поскольку это работа родительского элемента по удалению всех его дочерних элементов.

Как правило, правило таково:Если вы создали его, и он реализует IDisposable, утилизируйте его.Если вы ЕГО НЕ создавали, то НЕ удаляйте его, это задача родительского объекта.Но у каждого объекта могут быть особые правила, ознакомьтесь с документацией.

Для .net 3.5 в нем явно сказано "Утилизировать его, когда он больше не используется", так что это то, что я бы сделал.

Я вызываю dispose всякий раз, когда объект реализует IDisposeable .Это существует по какой-то причине.

Наборы данных могут быть огромными объемами памяти.Чем раньше они будут помечены для очистки, тем лучше.

Обновить

Прошло 5 лет с тех пор, как я ответил на этот вопрос.Я все еще согласен с моим ответом.Если существует метод dispose, он должен быть вызван, когда вы закончите с объектом.Интерфейс IDispose был реализован не просто так.

Если вашим намерением или контекстом этого вопроса действительно является сборка мусора, то вы можете явно присвоить datasets и datatables значение null или использовать ключевое слово using и позволить им выйти за рамки.Dispose делает не так много, как говорил ранее Tetraneutron.GC соберет объекты dataset, на которые больше нет ссылок, а также те, которые находятся вне области видимости.

Я действительно хотел бы, чтобы SO заставила людей отказаться от голосования на самом деле написать комментарий, прежде чем отклонять ответ.

Datasets реализует IDisposable тщательный MarshalByValueComponent, который реализует IDisposable.Поскольку наборами данных управляют, нет никакой реальной пользы от вызова dispose .

Попробуйте использовать функцию Clear().У меня это отлично подходит для утилизации.

DataTable dt = GetDataSchema();
//populate dt, do whatever...
dt.Clear();

Нет необходимости Dispose() поскольку DataSet наследует класс MarshalByValueComponent, а MarshalByValueComponent реализует IDisposable интерфейс

Прежде всего, я бы проверил, что Dispose делает с набором данных.Возможно, использование отражателя от redgate поможет.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top