DataSet和DataTable都实现了IDisposable,因此,根据传统的最佳实践,我应该调用它们的Dispose()方法。

然而,从我目前所读到的内容来看,DataSet和DataTable实际上没有任何非托管资源,因此Dispose()实际上并没有做太多工作。

另外,我不能只使用using(DataSet myDataSet…),因为DataSet有一个数据表的集合。

因此,为了安全起见,我需要遍历myDataSet。表,释放每个数据表,然后释放数据集。

那么,对我所有的数据集和数据表调用Dispose()是否值得呢?

附录:

对于那些认为数据集应该被处理的人: 一般来说,处理的模式是use using或try..最后,因为您希望保证Dispose()将被调用。

然而,对于集合来说,这很快就会变得很糟糕。例如,如果对Dispose()的调用之一抛出异常,该怎么办?是否吞下它(这是“坏的”)以便继续处理下一个元素?

或者,您是否建议我只调用myDataSet.Dispose(),而忘记在myDataSet.Tables中处理数据表?


数据集通过MarshalByValueComponent实现IDisposable,它实现了IDisposable。因为数据集是管理的,所以调用dispose并没有真正的好处。


每当一个对象实现IDisposeable时,我就调用dispose。它的存在是有原因的。

数据集可能占用大量内存。它们越早被标记为清理越好。

更新

我已经5年没有回答这个问题了。我仍然同意我的答案。如果存在dispose方法,则应该在处理完对象时调用该方法。实现IDispose接口是有原因的。


您应该假设它做了一些有用的事情并调用Dispose,即使它在当前的. net Framework版本中什么也不做。并不能保证它在未来的版本中会保持这种方式,从而导致低效的资源使用。


这里有几个讨论,解释了为什么Dispose对于DataSet不是必要的。

处理还是不处理?

DataSet中的Dispose方法存在只是因为继承的副作用——换句话说,它在终结中实际上没有做任何有用的事情。

应该在数据表和数据集对象上调用Dispose吗?其中包括一位最有价值球员的解释:

这个系统。数据命名空间(ADONET)不包含 非托管资源。因此,没有必要处理任何这些作为 只要你没有给自己加上什么特别的东西。

了解Dispose方法和数据集?有来自权威斯科特·艾伦的评论:

在实践中,我们很少处理数据集,因为它没有什么好处。”

所以,共识是,目前没有好的理由调用Dispose在一个数据集上。


如果您的意图或这个问题的上下文实际上是垃圾收集,那么您可以显式地将数据集和数据表设置为null,或者使用关键字using并让它们超出范围。Dispose并不像Tetraneutron之前说的那样。GC将收集不再引用的数据集对象以及超出范围的对象。

我真的希望SO能强迫人们在投票之前写一条评论。


即使对象没有非托管资源,通过打破对象图,处理也可以帮助GC。一般来说,如果一个对象实现了IDisposable,则应该调用Dispose()。

Dispose()是否实际执行某些操作取决于给定的类。对于DataSet, Dispose()实现继承自MarshalByValueComponent。它从容器中移除自身并调用dispose事件。源代码如下(用。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.Tables)通常是不需要的,因为父对象的工作是处理它所有的子成员。

一般来说,规则是:如果你创建了它并且它实现了IDisposable,那么就Dispose它。如果你没有创建它,那么不要处理它,这是父对象的工作。但每个对象可能有特殊的规则,检查文档。

对于。net 3.5,它明确地说“当不再使用时处理它”,所以这就是我要做的。


更新(2009年12月1日):

我想修改这个答案,并承认原来的答案有缺陷。

最初的分析确实适用于需要最终确定的对象——没有准确、深入的理解,实践不应该在表面上被接受的观点仍然成立。

然而,数据集、数据视图、数据表在它们的构造函数中抑制了终结——这就是为什么显式地在它们上调用Dispose()不做任何事情。

据推测,这是因为它们没有非托管资源;因此,尽管MarshalByValueComponent允许使用非托管资源,但这些特定的实现不需要,因此可以放弃终结。

(. net作者会注意抑制通常占用最多内存的类型的终结,这说明了这种实践对于可终结类型的重要性。)

尽管如此,自从。net框架出现以来(大约8年前),这些细节仍然没有得到充分的记录,这是相当令人惊讶的(你基本上只能靠自己的设备来筛选相互冲突的、模糊的材料,然后把它们拼凑在一起,这有时令人沮丧,但确实提供了对我们每天所依赖的框架的更完整的理解)。

经过大量阅读,我的理解如下:

If an object requires finalization, it could occupy memory longer than it needs to – here’s why: a) Any type that defines a destructor (or inherits from a type that defines a destructor) is considered finalizable; b) On allocation (before the constructor runs), a pointer is placed on the Finalization queue; c) A finalizable object normally requires 2 collections to be reclaimed (instead of the standard 1); d) Suppressing finalization doesn’t remove an object from the finalization queue (as reported by !FinalizeQueue in SOS) This command is misleading; Knowing what objects are on the finalization queue (in and of itself) isn’t helpful; Knowing what objects are on the finalization queue and still require finalization would be helpful (is there a command for this?) Suppressing finalization turns a bit off in the object's header indicating to the runtime that it doesn’t need to have its Finalizer invoked (doesn’t need to move the FReachable queue); It remains on the Finalization queue (and continues to be reported by !FinalizeQueue in SOS)

DataTable, DataSet, DataView类都植根于MarshalByValueComponent,这是一个可以(潜在地)处理非托管资源的可终结对象

Because DataTable, DataSet, DataView don’t introduce unmanaged resources, they suppress finalization in their constructors While this is an unusual pattern, it frees the caller from having to worry about calling Dispose after use This, and the fact that DataTables can potentially be shared across different DataSets, is likely why DataSets don’t care to dispose child DataTables This also means that these objects will appear under the !FinalizeQueue in SOS However, these objects should still be reclaimable after a single collection, like their non-finalizable counterparts

4(新参考资料):

http://www.devnewsgroups.net/dotnetframework/t19821-finalize-queue-windbg-sos.aspx http://blogs.msdn.com/tom/archive/2008/04/28/asp-net-tips-looking-at-the-finalization-queue.aspx http://issuu.com/arifaat/docs/asp_net_3.5unleashed http://msdn.microsoft.com/en-us/magazine/bb985013.aspx http://blogs.msdn.com/tess/archive/2006/03/27/561715.aspx

最初的回答:

关于这个问题有很多误导性的答案,通常都很糟糕——任何登陆这里的人都应该忽略噪音,仔细阅读下面的参考资料。

毫无疑问,Dispose应该在任何可终结对象上被调用。

我被冒犯了

调用Dispose可以显著加快内存的回收速度。

MarshalByValueComponent在Dispose()中调用GC.SuppressFinalize(this)——跳过这个意味着在内存回收之前必须等待几十个(如果不是数百个)Gen0集合:

With this basic understanding of finalization we can already deduce some very important things: First, objects that need finalization live longer than objects that do not. In fact, they can live a lot longer. For instance, suppose an object that is in gen2 needs to be finalized. Finalization will be scheduled but the object is still in gen2, so it will not be re-collected until the next gen2 collection happens. That could be a very long time indeed, and, in fact, if things are going well it will be a long time, because gen2 collections are costly and thus we want them to happen very infrequently. Older objects needing finalization might have to wait for dozens if not hundreds of gen0 collections before their space is reclaimed. Second, objects that need finalization cause collateral damage. Since the internal object pointers must remain valid, not only will the objects directly needing finalization linger in memory but everything the object refers to, directly and indirectly, will also remain in memory. If a huge tree of objects was anchored by a single object that required finalization, then the entire tree would linger, potentially for a long time as we just discussed. It is therefore important to use finalizers sparingly and place them on objects that have as few internal object pointers as possible. In the tree example I just gave, you can easily avoid the problem by moving the resources in need of finalization to a separate object and keeping a reference to that object in the root of the tree. With that modest change only the one object (hopefully a nice small object) would linger and the finalization cost is minimized. Finally, objects needing finalization create work for the finalizer thread. If your finalization process is a complex one, the one and only finalizer thread will be spending a lot of time performing those steps, which can cause a backlog of work and therefore cause more objects to linger waiting for finalization. Therefore, it is vitally important that finalizers do as little work as possible. Remember also that although all object pointers remain valid during finalization, it might be the case that those pointers lead to objects that have already been finalized and might therefore be less than useful. It is generally safest to avoid following object pointers in finalization code even though the pointers are valid. A safe, short finalization code path is the best.

从那些在第2代中看过100多mb的非引用数据表的人那里吸取经验:这是非常重要的,并且完全被本文的答案遗漏了。

引用:

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-finali zedispose-pattern.aspx

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


尝试使用Clear()函数。 这对我来说很有用。

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

不需要Dispose() 因为DataSet继承了MarshalByValueComponent类,而MarshalByValueComponent实现了IDisposable接口


这是正确处置数据表的方法。

private DataTable CreateSchema_Table()
{
    DataTable td = null;
    try
    {
        td = new DataTable();
        //use table DataTable here
        
        return td.Copy();
    }
    catch {  }
    finally
    {
        if (td != null)
        {
            td.Constraints.Clear();
            td.Clear();
            td.Dispose();
            td = null;
        }
    }
}

这可能是处置和释放DataSet所消耗的内存的最佳/适当的方式。

try
    {
        DataSet ds = new DataSet("DS");
        //use table DataTable here
        
    }
    catch {  }
    finally
    {
        if (ds != null)
                {
                    ds.EnforceConstraints = false;
                    ds.Relations.Clear();
                    int totalCount = ds.Tables.Count;

                    for (int i = totalCount - 1; i >= 0; i--)
                    {
                        DataTable td1 = ds.Tables[i];
                        if (td1 != null)
                        {
                            td1.Constraints.Clear();
                            td1.Clear();
                            td1.Dispose();
                            td1 = null;
                        }
                    }

                    ds.Tables.Clear();
                    ds.Dispose();
                    ds = null;
                }
    }