And*_*nck 37 c# dispose winforms
如果我不调用此代码段中Dispose
的pen
对象会发生什么?
private void panel_Paint(object sender, PaintEventArgs e)
{
var pen = Pen(Color.White, 1);
//Do some drawing
}
Run Code Online (Sandbox Code Playgroud)
Dav*_*ack 28
这里应该做一些修正:
关于Phil Devaney的答案:
"......调用Dispose允许您进行确定性清理,强烈推荐."
实际上,调用Dispose()并不能确定性地导致.NET中的GC集合 - 即它不会因为您调用Dispose()而立即触发GC.它只向GC间接发出信号,表示在下一次GC期间可以清除对象(对象所在的生成).换句话说,如果对象位于第1代,则在第1代收集发生之前不会将其处理掉.可以通过编程和确定性地使GC执行集合的唯一方法(尽管不是唯一的方法)是调用GC.Collect().但是,建议不要这样做,因为GC会在运行时通过收集有关应用程序运行时内存分配的指标来"调整"自身.调用GC.Collect()会转储这些指标并导致GC重新开始"调整".
关于答案:
IDisposable用于处理非托管资源.这是.NET中的模式.
这是不完整的.由于GC是非确定性的,因此可以使用Dispose Pattern(如何正确实现Dispose模式),以便您可以释放您正在使用的资源 - 托管或非托管.它与您发布的资源无关.实现Finalizer的需要与您正在使用的资源类型有关 - 即,如果您具有非可终结(即本机)资源,则仅实现一个资源.也许你会混淆两者.顺便说一句,你应该避免使用SafeHandle类来实现Finalizer,而不是包装通过P/Invoke或COM Interop封送的本机资源.如果最终实现了Finalizer,则应始终实现Dispose Pattern.
我还没有看到任何人提到的一个重要注意事项是,如果创建了一次性对象并且它有一个Finalizer(并且你从未真正知道它们是否存在 - 并且你当然不应该对此做出任何假设),那么它将会直接发送到Finalization Queue并进行至少1次额外的GC收集.
如果最终未调用GC.SuppressFinalize(),则将在下一个GC上调用该对象的终结器.请注意,Dispose模式的正确实现应该调用GC.SuppressFinalize().因此,如果在对象上调用Dispose()并且它已正确实现了模式,则将避免执行Finalizer.如果不对具有终结器的对象调用Dispose(),则该对象将在下一个集合上由GC执行其Finalizer.为什么这么糟糕?CLR中的Finalizer线程(包括.NET 4.6)是单线程的.想象一下如果你增加这个线程的负担会发生什么 - 你的应用程序性能会告诉你在哪里.
在对象上调用Dispose可提供以下内容:
编辑:我刚刚注意到IDisposable (这里极端讽刺)的"所有知道并且始终正确"的MSDN文档确实说
此接口的主要用途是释放非托管资源
任何人都应该知道,MSDN远非正确,从未提及或显示"最佳实践",有时提供不编译的示例等.不幸的是,这些都记录在这些文字中.但是,我知道他们想说的是:在一个完美的世界里,GC会为你清理所有管理的资源(多么理想化); 然而,它不会清理非托管资源.这绝对是真的.话虽这么说,生活并不完美,也没有任何应用. GC只会清理没有rooted-references的资源. 这主要是问题所在.
在.NET可以"泄漏"(或不释放)内存的大约15-20种不同方式中,如果不调用Dispose(),最有可能咬你的方法是取消注册/取消挂起/取消/拆除事件处理器/代表.如果您创建一个具有与其连接的委托的对象,并且您没有在其上调用Dispose()(并且不自行分离委托),则GC仍会将该对象视为具有root权限的引用 - 即委托.因此,GC永远不会收集它.
@joren的评论/问题如下(我的回复太长,无法发表评论):
我有一篇关于我建议使用的Dispose模式的博客文章 - (如何正确实现Dispose模式).有些时候你应该删除引用,它永远不会伤害这样做.实际上,这样做会在GC运行之前做一些事情 - 它会删除对该对象的root权限引用.GC稍后会扫描其根植入的集合,并收集那些没有根参考的参考.想想这个例子,当这样做是好的时候:你有一个类型为"ClassA"的实例 - 我们称之为'X'.X包含一个"ClassB"类型的对象 - 让我们称之为'Y'.Y实现了IDisposable,因此,X应该做同样的事情来处理Y.假设X在第2代或LOH中,Y在第0代或第1代.当在X上调用Dispose()并且该实现为空时引用Y,立即删除对Y的有根引用.如果Gen 0或Gen 1发生GC,则清除Y的内存/资源,但X的内存/资源不是因为X存在于Gen 2或LOH中.
jas*_*son 25
该Pen
会由GC在未来某个不确定的点进行收集,你是否不叫Dispose
.
但是,笔不会清除笔所持有的任何非托管资源(例如,GDI +句柄).GC仅清理托管资源.通过呼叫Pen.Dispose
,您可以确保及时清理这些非托管资源,并确保不泄漏资源.
现在,如果Pen
有一个终结器并且终结器清理了非托管资源,则当Pen
收集垃圾时,将清除那些所述非托管资源.但重点是:
Dispose
明确调用,以便释放非托管资源,并且Pen
实施IDisposable
.IDisposable
用于处置非托管资源.这是.NET中的模式.
有关此主题的先前评论,请参阅此答案.
Phi*_*ney 13
在将来某些不确定的时间,即Pen对象被垃圾收集并调用对象的终结器时,底层GDI +笔柄将不会被释放.这可能不会在流程终止之前,或者可能更早,但重点是它是非确定性的.调用Dispose允许您进行确定性清理,强烈建议使用.
归档时间: |
|
查看次数: |
11734 次 |
最近记录: |