[英]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标记的配对,因此您不会忘记结束标记。
不, Pen
和Brush
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,它应该解决你的问题并解释其后果。
虽然你问过钢笔和画笔,但Font是一个有一些奇怪怪癖的类。 特别是,如果为了设置控件的Font属性而创建一个字体,则仍然负责处理该字体 - 所有权不会转移到控件 - 但是可以通过处理该字体来执行该任务。任何时候 - 即使一旦创建了字体,在将其分配给控件之前。 似乎Font是托管信息对象和非托管GDI资源的组合,出于某些目的,只需要前者。 奇怪的设计 - 字体应该是两个类。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.