繁体   English   中英

我是否需要在托管对象上调用Dispose()?

[英]Do I need to call Dispose() on managed objects?

我无法相信我仍然对此感到困惑但是,无论如何,让我们最终指出:

我有一个类覆盖OnPaint来做一些绘图。 为了加快速度,我在构造函数中预先创建了笔,画笔等,以便OnPaint不需要继续创建和处理它们。

现在,我确保我总是处理这些对象,但我感觉我不需要,因为尽管它们实现了IDisposable,但它们都是托管对象。

这个对吗?


感谢所有的答案,这个问题肯定已被钉上了。
我很高兴我一直保持警惕,总是使用'​​使用',所以我不需要经历所有的代码检查。 我只想清楚我不是一个毫无意义的用户。

顺便说一句,我确实有一个奇怪的情况,最近,我不得不更换一个使用块并手动调用dispose! 我会把它挖出来并创造一个新问题。

这是正确的。 您需要处置实现IDisposable对象。 这就是他们实现IDisposable - 指定它们(直接或间接)包装非托管资源的事实。

在这种情况下,非托管资源是GDI句柄,如果在实际使用它们时未能处理它们,则会泄漏这些句柄。 现在这些特定对象具有终结器 ,这些终结器将导致在GC启动时释放资源,但您无法知道何时会发生这种情况。 从现在开始可能是10秒,可能是10天后; 如果你的应用程序没有产生足够的内存压力导致GC启动并在那些画笔/笔/字体/等上运行终结器,那么在GC实现正在发生的事情之前,你最终可能会使GDI资源的操作系统挨饿。

此外,您无法保证每个非托管包装器实际上都实现了终结器。 .NET Framework本身是非常一致的,因为实现IDisposable类使用正确的模式实现它,但是其他类完全可能有一个不包含终结器的破坏的实现,因此不能正确清理,除非在其上显式调用Dispose 一般来说, IDisposable的目的是你不应该知道或关心具体的实现细节; 相反,如果它是一次性的,那么你处理它,期间。

故事的道德:始终处置IDisposable对象。 如果您的类“拥有” IDisposable对象,那么它应该实现IDisposable本身。

你需要处理它们。

托管对象自己管理自己的记忆 但是内存不是对象使用的唯一资源。 Dispose()旨在释放其他资源。

你的方法有一个明显的讽刺。 通过预先创建笔/画笔,您正在创建 Dispose()尝试解决的问题。 那些GDI对象将会更长,就像你不调用Dispose()时一样。 事实上更糟糕的是,它们至少会在表格关闭之前出现。

它们可能已经足够长,可以晋升为第二代。 垃圾收集器不经常进行第2代收集,现在重要的是在它们上调用Dispose()。 通过将表单的Dispose()方法从Designer.cs文件移动到form.cs文件并添加Dispose调用来完成此操作。

但是,这是正确的方式。 钢笔和刷子是非常便宜的物体。 在Paint事件中,在需要时创建它们。 并使用using语句,以便它们立即处理。 使用秒表类重新确保自己这实际上不会导致任何减速。

我写了一个GDI +图表组件,它使用了很多笔和画笔。 我创建了它们并将它们放在正在进行绘制的代码块中,性能从来都不是问题。 更好的是,在操作系统恕我直言中有一个长寿的句柄。

你有没有对此进行分析,看看创建和处理这些对象是否确实存在问题? 我认为不是。

通过遵循create-in-a-using-block模式,您可以使自己的事情变得更容易,而且更容易出错。

如果您确实想要创建它们一次,那么还要在您拥有的类上实现IDisposable,并在您拥有的对象上迭代Dispose。 不需要析构函数(终结器)。

对不需要Dispose的对象执行此操作几乎没有任何成本,但如果忘记对需要它的对象进行Dispose,则会产生很大的成本。

不,IDisposable适用于使用非托管资源的托管对象。 通常,您应该在完成后始终处置它们。

你真的需要查看刷子,笔等的文档。

如果他们没有使用非托管资源,您可能不必调用Dispose。 但是使用/ Dispose模式有时会被“误用”。 作为示例,请考虑ASP.NET MVC框架。 在这里你可以这样写:

using(Html.BeginForm(...)){
  ///HTML input fields etc.
}

调用Html.BeginForm(...) ,将输出FORM标记。 当using语句结束时,将在从Html.BeginForm(...)返回的对象上调用Dispose 调用Dispose会导致生成结束FORM标记。 通过这种方式,编译器实际上将强制执行FORM标记的配对,因此您不会忘记结束标记。

不, PenBrush es 不是完全管理的对象。

它们包含非托管资源的句柄,即底层图形系统中的相应GDI对象。 (不确定这里的确切术语......)

如果您不处理它们,在垃圾收集器完成对象之前不会释放手柄,并且无法保证它很快就会发生,或者根本不会发生。

不,这是错的。 我同意Aaronaught的观点。

此外,Microsoft建议在2003年中期的Don Box网络广播中,每个.Net开发人员都应该处理他们自己的对象,无论是托管还是非托管,因为这会使代码性能提高20%。 如果做得好,它可以显着改善性能。 因此它是每个.net开发人员需要知道和使用的核心技能。

其他人提到“使用”块用于GDI对象 - 这是一个代码示例:

using( var bm = new Bitmap() )
using( var brush = new Brush() )
{

   // code that uses the GDI objects goes here
   ...

} // objects are automatically disposed here, even if there's an exception

请注意,您可以为单个代码块添加任意数量的“使用”行。

我认为这是处理Disposable对象的一种很好,干净的方法。

在类似的帖子上看到我的答案。 如果你不打电话给Dispose,它应该解决你的问题并解释其后果。

如果我不在Pen对象上调用Dispose会发生什么

虽然你问过钢笔和画笔,但Font是一个有一些奇怪怪癖的类。 特别是,如果为了设置控件的Font属性而创建一个字体,则仍然负责处理该字体 - 所有权不会转移到控件 - 但是可以通过处理该字体来执行该任务。任何时候 - 即使一旦创建了字体,在将其分配给控件之前。 似乎Font是托管信息对象和非托管GDI资源的组合,出于某些目的,只需要前者。 奇怪的设计 - 字体应该是两个类。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM