38

我对学习 C#(来自 Java 和 C++ 背景)相当陌生,并且我有一个关于手动垃圾处理的问题:甚至可以手动销毁 C# 中的对象吗?我知道IDisposable接口,但是假设我正在处理一个我没有编写并且没有实现它的类?它没有一个.Dispose()方法,所以并且using { }已经出局,并且.Finalize总是非此即彼protectedprivate这也不是一个选项。

(在这种情况下,我只是想了解 C# 中的可能性。我想如果一切都失败了,我可以继承假设的ImNotDisposable类,以便它实现IDisposable。)

4

8 回答 8

36

您不会手动销毁 .Net 对象。这就是托管环境的全部意义所在。

事实上,如果对象实际上是可访问的,这意味着您有一个引用可以用来告诉 GC 您要销毁哪个对象,那么收集该对象将是不可能的。GC永远不会收集任何仍然可以访问的对象。

您可以做的是调用GC.Collect()强制进行一般收集。然而,这几乎从来都不是一个好主意。

相反,最好简单地假装任何不使用非托管资源并且程序中任何其他对象都无法访问的对象立即被销毁。我知道这不会发生,但此时对象只是一块内存,就像其他任何东西一样;你无法收回它,它最终会被收集起来,所以它对你来说也可能是死的。

最后一点关于IDisposable. 您应该只将它用于包装非托管资源的类型:诸如套接字、数据库连接、gdi 对象等,以及偶尔的事件/委托订阅。

于 2009-12-31T21:59:35.787 回答
9

如果对象不可访问,那么您可以调用GC.Collect()并且对象将被销毁。的概念IDisposable与 CLR 无关,主要是供用户代码实现以执行额外的处理逻辑。对对象调用 Dispose() 不会从内存中释放对象本身,尽管它很可能会释放该对象引用的任何资源。

我应该补充一点,虽然我所说的是实现这一点的一种方法,但在 99.9999% 的应用程序中,你永远不应该调用GC.Collect()它,因为它通常会降低应用程序的性能而不是改进它。

于 2009-12-31T21:57:31.290 回答
8

尽管您可以触发垃圾回收(您需要为所有代触发 GC,因为您无法确定可终结对象在哪一代),但您不一定强制特定对象的终结。您只能依赖关于垃圾收集器如何工作的假设。

Furtnermore,由于终结发生在它自己的线程上,你应该在触发垃圾回收后调用WaitForPendingFinalizers 。

GC.Collect(GC.MaxGeneration);
GC.WaitForPendingFinalizers();

正如其他人所指出的,这实际上会损害您的应用程序的性能,因为不必要地调用 GC 可以将原本寿命较短的对象提升到更高的世代,这些世代的收集成本更高且收集频率更低。

一般来说,实现终结器(析构函数)但不实现 IDisposable 的类是不受欢迎的。任何实现 IDisposable 的东西都应该调用它的终结器逻辑,并在垃圾收集时抑制自己的终结。

Jeff Richter 最近发布了一个很好的小技巧,用于在垃圾收集发生时接收通知

Rico Mariani (MSFT)关于垃圾收集器基础知识和性能提示的另一篇精彩文章

于 2009-12-31T22:06:00.743 回答
7

不,您不能破坏特定对象。

可以调用垃圾收集器,它会寻找要销毁的对象,但这几乎不是一个好主意。

于 2009-12-31T21:58:36.577 回答
4

可以在要销毁的变量超出范围后强制垃圾收集器运行,但您通常不希望这样做,因为如果让垃圾收集器自行工作,效率会更高。

强制垃圾收集可以用GC.Collect完成,但不要这样做。在我作为 .NET 开发人员的 10 年中,我从来不需要它。

于 2009-12-31T21:59:54.420 回答
2

不可能以确定的方式销毁对象。CLR 确定何时回收标记的对象。这意味着虽然您可以标记要回收的对象并确保整理托管和非托管资源以进行处置(通过实现 IDisposable 模式),但释放内存的实际时间取决于 CLR。这与 C++ 不同,在 C++ 中您可以实际删除某些内容,然后将其释放。

于 2009-12-31T22:01:18.190 回答
2

不能手动销毁一个对象“像 C++ 删除”,你能做的就是关闭对象获得的任何独占资源并将对该对象的所有引用都清空,这样 GC 可以收集它,也不要调用 GC .Collect() 自己,GC 过程很昂贵,因为它必须暂停所有其他线程才能安全地从内存中收集对象,所以只要相信 GC,它会在需要时启动。

于 2009-12-31T22:02:15.523 回答
1

假设您有一个类矩阵,并且创建了两个矩阵对象aMatrixbMatrix. 在 C# 中,您可以像这样手动销毁(最终确定)一个对象:

aMatrix = null;

GC.Collect();

垃圾收集器会注意到您aMatrix的值为 null 并将销毁(最终确定)它。这是否是一个好主意是另一回事。

于 2017-08-14T11:40:30.237 回答