20

对于一般代码,我真的需要处置一个对象吗?我可以在大多数情况下忽略它,还是在您 100% 确定不再需要它时始终处置它是个好主意?

4

8 回答 8

27

处理完物品后立即处理它。一次性对象表示持有 CLR 本质上不知道的有价值资源的对象。因此,GC 也不知道资源,也无法就何时应该收集一次性对象并因此释放底层资源做出明智的决定。

最终 GC 会感到内存压力并巧合地收集您的对象(仅此而已)。如果您不以确定的方式处理对象,那么完全有可能进入几乎没有内存压力的资源匮乏状态。

这是如何发生的快速示例。让我们将底层资源视为 Win32 句柄。这些是非常有限且相当小的。您运行一个创建大量 Foo 对象的操作。Foo 对象实现 IDisposable 并负责创建和处置 Win32 句柄。它们不是手动释放的,而是通过不同的怪癖使其进入 Gen2 堆。这个堆很少被释放。随着时间的推移,足够多的 Foo 实例进入 Gen2 堆以占用所有可用句柄。因此,无论使用多少内存,都无法创建新的 Foo 对象。

实际上,要释放句柄,需要在单个操作期间分配相当大量的内存才能提供足够的压力来释放实例。

于 2008-10-29T05:36:35.713 回答
15

如果对象实现了 IDisposable,则应在完成后立即处理它。最简单的方法是用using块包围它:

using (SqlCommand cmd = new SqlCommand(conn)) {
    cmd.ExecuteNonQuery();
}
于 2008-10-29T05:14:57.647 回答
6

您应该始终调用Dispose()任何实现的类型的原因IDisposable是它通常用于表示该类型获取非托管资源。尤其重要的是要尽可能早地释放它们。正如其他人所提到的,using这是执行此操作的首选方法。

于 2008-10-29T05:34:53.750 回答
3

有几种方法可以查看它。一种方法试图确定是否真的有必要在不再需要对象时立即处理它,例如使用 Reflector 来查看它是否真的持有非托管资源,或者如果它们被偶然处置。另一种观点是假设如果一个对象实现了 IDisposable,那么确定是否真的需要调用 Dispose() 不是你的事——你总是调用它。我认为这是正确的方法。窥视对象的私有实现以决定如何使用它们会增加与可能更改的实现耦合的风险。一个例子是 LINQ to SQL DataContext。它实现了 IDispose,但主要是在不需要显式调用 Dispose() 的情况下自行清理。我的偏好是编写无论如何都明确处理的代码,但其他人认为它没有必要。

当然,这一切都适用于实现 IDisposable 的对象。确实,GC 会在您没有任何明确操作的情况下处理大多数其他事情,但是值得阅读一下关于 GC 行为的微妙之处(我现在太累了,无法考虑细节)以了解何时显式地处理对象,更重要的是,何时实现 IDispose。网上有很多关于这件事的好文章。

如前所述, using(..) { ... } 是 IDisposable 实现者的朋友。

于 2008-10-29T05:34:44.657 回答
1

如果对象实现了 IDisposable,那么它很可能会占用非托管资源。因此,经验法则是在您完成对象的那一刻调用 Dispose,直接或通过 using 块。不要依赖 GC,因为这就是 IDisposable 的用途 - 资源的确定性释放。

于 2008-10-29T06:38:11.783 回答
0

不,在您没有持有非托管资源的情况下,您可以通过调用 Dispose 逃脱。但是如果你的类持有一个非托管资源,比如一个需要删除的临时文件,那么你将不得不显式调用 Dispose。

您可以通过在 Finalize 方法中编写释放代码来避免调用 Dispose,但是您依赖于垃圾收集器,因为您永远无法确定垃圾收集器何时会完成您的对象。为了安全起见,如果您正在设计这样一个包含非托管资源的类,您可以在 Dispose 和 Finalize 方法中编写相同的对象释放代码,但如果这样做,请始终在您的 dispose 方法中使用 SuppressFinalize()因为如果您的对象已经在终结队列中,它将阻止调用 Finalize() 方法。

于 2008-10-29T08:21:19.017 回答
-1

在大多数情况下,依靠 GC '工作'。典型的例外是当您有大量资源交互时 - 在这种情况下,最好明确处置。

明显的例如。

using (var conn = new SqlConnection(connString)) {}

“使用”块绝对是确保正确处理对象的最干净、最可靠的方法。“使用”块可以与任何实现 IDisposable 的对象一起使用。

于 2008-10-29T05:15:58.017 回答
-7

当你完成一个对象时,你可以忘记它。只要它没有在任何地方被引用,那么它就和消失一样好。当垃圾收集器喜欢它时,它使用的内存就会被释放。

于 2008-10-29T05:20:31.270 回答