Должен ли я Dispose () DataSet и DataTable?

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

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

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

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

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

дополнение:

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

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

или вы предлагаете мне просто позвонить в myDataSet.Dispose () и забудьте о размещении DataTables в myDataSet.Столы?

10 ответов


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

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

метод Dispose в DataSet существует только из-за побочного эффекта наследования-другими словами, он фактически не делает ничего полезного в завершении.

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

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

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

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

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


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

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

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

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

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

(что авторы .NET позаботятся о том, чтобы подавить завершение на тех самых типах, которые обычно занимают больше всего памяти говорит о важности этой практики в целом для завершаемых типов.)

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

после большого количества чтения, вот мое понимание:

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

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

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

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

4 (новый литература):

Оригинал Ответ:

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

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

DataTables are Finalizable.

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

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

с этим основным пониманием завершения мы уже можно вывести некоторые очень важные вещи:

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

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

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

возьмите его от кого-то, кто видел 100s MBs без ссылок DataTables в 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, даже если он ничего не делает в текущем . Воплощения NET Framework, нет никакой гарантии, что он останется таким в будущих версиях, ведущих к неэффективному использованию ресурсов.


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

действительно ли Dispose () что-то делает или нет, зависит от данного класса. В случае DataSet реализация Dispose () наследуется от MarshalByValueComponent. Он удаляет себя из контейнера и вызывает событие Disposed. Исходный код приведен ниже (разобран с помощью .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);
                }
            }
        }
    }
}

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

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

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


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

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

обновление

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


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

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


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


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

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

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