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


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

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

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

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

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

дополнение:

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

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

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

10 179

10 ответов:

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

утилизировать или не утилизировать ?:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

DataTables are Финализируемых.

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

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

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

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

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

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

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

ссылки:

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

2 - http://vineetgupta.spaces.live.com/blog/cns!8DE4BDC896BEE1AD! 1104. entry 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, разбив графы объектов. В общем случае, если объект реализует 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);
                }
            }
        }
    }
}

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

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

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

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

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

обновление

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

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

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

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

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

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

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