我应该Dispose()DataSet和DataTable吗?

DataSet和DataTable都实现了IDisposable,所以,通过传统的最佳实践,我应该调用他们的Dispose()方法。

但是,从目前为止我读到的内容来看,DataSet和DataTable实际上并没有任何非托管资源,因此Dispose()实际上并没有太多的功能。

另外,我不能只使用using(DataSet myDataSet...)因为DataSet有一组DataTables。

所以,为了安全起见,我需要遍历myDataSet.Tables,处理每个DataTable,然后处理DataSet。

那么,在我所有的DataSets和DataTables上调用Dispose()是否值得麻烦?

附录:

对于那些认为应该处置DataSet的人:通常,处置模式是使用usingtry..finally ,因为您要确保Dispose()将被调用。

然而,这对于一个集合来说真的很难实现。 例如,如果对Dispose()的调用之一抛出异常,你会怎么做? 你是否吞下它(这是“坏”),以便继续处理下一个元素?

或者,你是否建议我只调用myDataSet.Dispose(),而忘记在myDataSet.Tables中配置DataTables?


这里有几个讨论解释为什么Dispose不需要DataSet。

处置还是不处理?:

DataSet中的Dispose方法仅仅因为继承的副作用而存在 - 换句话说,它并没有在最终化中实际做任何有用的事情。

应该在DataTable和DataSet对象上调用Dispose吗? 包括MVP的一些解释:

system.data名称空间(ADONET)不包含非托管资源。 因此,只要你没有给自己添加特别的东西,就没有必要去处理这些东西。

了解Dispose方法和数据集? 有权威评论Scott Allen:

在实践中,我们很少放弃DataSet,因为它几乎没有什么好处“

所以,目前的共识是, 目前没有理由在DataSet上调用Dispose。


更新(2009年12月1日):

我想修改这个答案,并承认最初的答案是有缺陷的。

最初的分析确实适用于需要最终确定的对象 - 并且如果没有准确的深入理解,实践不应该被接受的观点依然存在。

然而,事实证明,DataSets,DataViews,DataTables 在它们的构造函数中抑制了终结 - 这就是为什么对它们调用Dispose()显式不做任何事情的原因。

据推测,这是因为他们没有非托管资源; 所以尽管MarshalByValueComponent为非托管资源提供了许可,但这些特定的实现不需要,因此可以放弃最终确定。

(.NET作者会小心地抑制通常占用大部分内存的类型的最终定义,这说明这种做法对于可终结类型的重要性。)

尽管如此,自从.NET Framework开始(大约8年前)以来,这些细节仍然没有详细记录,这是相当令人惊讶的(您基本上只能将自己的设备放在自己的设备上筛选相互矛盾或模糊的材料,有时令人沮丧,但确实提供了对我们每天所依赖的框架的更全面的理解)。

大量阅读后,我的理解是:

如果一个对象需要最终化,它可能占用的内存比它需要的时间长 - 这是为什么:a)定义析构函数的任何类型(或从定义析构函数的类型继承)被认为是可终止的; b)分配时(在构造函数运行之前),指针放置在Finalization队列中; c)可终结对象通常需要回收2个集合 (而不是标准1); d)抑制终结不会从终结队列中删除一个对象(如SOS中的!FinalizeQueue所报告的)该命令具有误导性; 知道最终化队列中的对象(本身)是没有用的; 知道最终化队列中的对象是什么并且仍然需要最终确定会很有帮助(是否有这样的命令?)

抑制结束会在对象的头部稍微偏离一点,向运行时指示它不需要调用Finalizer(不需要移动FReachable队列); 它仍然在Finalization队列中(并继续由SOS中的FinalizeQueue报告)

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

  • 由于DataTable,DataSet,DataView不引入非托管资源,因此它们会在其构造函数中抑制终结
  • 虽然这是一种不寻常的模式,但它使得调用者不必担心在使用后调用Dispose
  • 这一点以及DataTable可能跨不同DataSet共享的事实很可能是为什么DataSets不关心处理子DataTable
  • 这也意味着这些对象将出现在SOS中的!FinalizeQueue下
  • 但是,这些对象在收集完成后仍然应该可以收回,就像它们的不可终止的对象一样
  • 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
  • 原始答案:

    在这方面有很多误导性的,通常很差的答案 - 任何登陆这里的人都应该忽略噪音并仔细阅读下面的参考文献。

    毫无疑问, 应该在任何Finalizable对象上调用Dispose。

    数据表是可定制的。

    调用Dispose可显着加快内存回收速度。

    MarshalByValueComponent在其Dispose()中调用GC.SuppressFinalize(this) - 跳过这意味着在内存被回收之前必须等待数十甚至数百个Gen0集合:

    有了这个对定稿的基​​本理解,我们可以推断出一些非常重要的东西:

    首先,需要最终确定的对象比没有确定对象的对象活得更长。 事实上,他们可以活得更久。 例如,假设gen2中的一个对象需要完成。 定稿将按计划进行,但对象仍在gen2中,因此在下一代gen2收集发生之前不会重新收集。 这可能确实是一个很长的时间,事实上,如果事情进展顺利,这将是一段很长的时间,因为gen2集合是昂贵的,因此我们希望它们很少发生。 需要完成的旧对象可能需要等待几十个甚至几百个gen0集合才能回收它们的空间。

    其次,需要最终确定的物体会造成附带损害。 由于内部对象指针必须保持有效,不仅直接需要结束的对象会留在内存中,而且对象直接或间接引用的所有对象也将保留在内存中。 如果一个巨大的物体树被一个需要敲定的单个物体锚定,那么整棵树就会像我们刚刚讨论过的那样长时间滞留。 因此,谨慎使用终结器并将它们放置在尽可能少有内部对象指针的对象上非常重要。 在我刚刚给出的树例子中,您可以通过将需要定型的资源移动到单独的对象并在树的根中保留对该对象的引用,从而轻松避免该问题。 随着这种适度的变化,只有一个对象(希望是一个漂亮的小物体)会徘徊,最终成本降到最低。

    最后,需要最终化的对象为终结器线程创建工作。 如果你的最终化过程是复杂的,那么唯一的终结者线程将花费大量的时间来执行这些步骤,这可能会导致工作积压,并因此导致更多的对象等待终结。 因此,终结者做尽可能少的工作是非常重要的。 还要记住,虽然所有对象指针在最终确定期间保持有效,但这些指针可能会导致已经完成的对象,因此可能不太有用。 尽管指针是有效的,但避免在最终代码中使用后续对象指针通常最安全。 安全,简短的终结代码路径是最好的。

    从在Gen2中看到100个未引用的DataTable的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使用集电极 - 性能 - finalizedispose-pattern.aspx

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


    你应该假定它做了一些有用的事情,并且称它为Dispose,即使它在当前没有做任何事情。 NET Framework的化身,但并不能保证它将在未来的版本中保持这种方式,从而导致资源使用效率低下。

    链接地址: http://www.djcxy.com/p/9223.html

    上一篇: Should I Dispose() DataSet and DataTable?

    下一篇: Anyone know a good workaround for the lack of an enum generic constraint?