手动销毁C#对象

Eas*_*ere 33 c# destructor idisposable using

我对学习C#(来自Java和C++背景)相当新,我对手动垃圾处理有疑问:是否有可能手动销毁C#中的对象?我知道IDisposable接口,但是假设我正在处理一个我没写过的类而且它没有实现它?它不会有一个.Dispose()方法,使和using { }超出,并且.Finalize始终为protected还是private这样,要么是不是一种选择.

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

Joe*_*orn 31

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

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

你可以做的是打电话GC.Collect()强制一般收藏.但是,这几乎从来都不是一个好主意.

相反,最好只是假装任何不使用非托管资源且程序中任何其他对象无法访问的对象立即被销毁.我知道这不会发生,但在这一点上,对象只是一块内存,就像其他任何一样; 你不能收回它,它最终会被收集,所以你可能也死了.

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

  • 我还使用dispose取消链接我连接到外部对象的任何事件.如果不这样做,则在外部对象出现之前,不会从内存中删除该对象,这可能是应用程序的生命周期. (4认同)

Eil*_*lon 7

如果无法访问该对象,则可以调用GC.Collect()该对象并将其销毁.这个概念IDisposable与CLR无关,主要是用户代码实现执行额外的处理逻辑.在对象上调用Dispose()不会将对象本身从内存中释放出来,尽管它可以很好地处理此对象引用的任何资源.

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

  • 调用`GC.Collect()`不是你应该做的事,除非它是*非常好的理由. (4认同)
  • 如果对象a具有对对象b的引用,并且b具有对a的引用,则引用a和b两者(AKA为循环引用).但是,如果没有其他人对a或b都有引用,那么两者都不可访问,垃圾收集器将终止它们(最终). (4认同)
  • @Cecil:是的,它可能会影响性能.想象一下,即使没有任何东西可以收集,或者当你的应用程序繁忙时强制收集,强制主线程停止收集.更糟糕的是,因为垃圾收集器是世代的,你可以强迫对象进入一个真正不应该这样做的更长的生活世代. (4认同)
  • 它不是关于对象的引用 - 它是关于可达性(我提到的). (2认同)
  • 时间不参与GC性能.一切都与分配内存的频率和内容有关.将呼叫间隔分开的事实意味着什么 - 如果没有发生正常诱导的GC,那么您可能会不必要地将对象推向更高代,这会影响性能.特别是在长期运行的应用和服务中. (2认同)

Jos*_*osh 7

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

更确切地说,由于终结发生在它自己的线程上,你应该在触发垃圾收集后调用WaitForPendingFinalizers.

GC.Collect(GC.MaxGeneration);
GC.WaitForPendingFinalizers();
Run Code Online (Sandbox Code Playgroud)

正如其他人所指出的,这实际上可能会损害您的应用程序的性能,因为不必要地调用GC可以将其他短期对象推向更高代,这些对象收集起来更昂贵并且收集频率更低.

一般来说,实现终结器(析构函数)并且不实现IDisposable的类是不受欢迎的.任何实现IDisposable的东西都应该调用它的终结器逻辑并且在垃圾收集中完成自定义.

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

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


Jay*_*uzi 6

不,你不能销毁一个特定的对象.

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


Mar*_*ann 5

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

可以使用GC.Collect强制进行垃圾回收,但不要这样做。在我作为 .NET 开发人员的 10 年里,我从未需要过它。