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

时间:2023-02-09 15:57:04

I can't believe I'm still confused about this but, any way, lets finally nail it:

我真不敢相信我还是搞不清楚,但是,无论如何,让我们最终确定:

I have a class that overrides OnPaint to do some drawing. To speed things up, I create the pens, brushes etc before hand, in the constructor, so that OnPaint does not need to keep creating and disposing them.

我有一个类,它可以重写油漆做一些绘图。为了加快速度,我在构造函数中创建笔、笔刷等等,这样OnPaint就不需要继续创建和处理它们。

Now, I make sure that I always dispose of such objects, but I have the feeling I don't need to because, despite the fact they implement IDisposable, they're managed objects.

现在,我确保我总是处理这些对象,但是我有一种感觉,我不需要这样做,因为,尽管它们实现了IDisposable,它们是被管理的对象。

Is this correct?

这是正确的吗?


Thanks for all the answers, the issue has certainly been nailed.
I'm glad I've been vigilant in always using 'using' so that I don't need to go through all my code checking. I just wanted to be clear that I wasn't being a pointless user.

谢谢大家的回答,这个问题已经解决了。我很高兴我一直在使用“use”,这样我就不需要检查所有的代码了。我只是想表明我不是一个毫无意义的用户。

As an aside, I did have a strange situation, recently, where I had to replace a using block and manually call dispose! I'll dig that out and create a new question.

顺便说一句,我最近遇到了一个奇怪的情况,我必须替换using块并手动调用dispose!我将挖掘出来,并创建一个新的问题。

12 个解决方案

#1


43  

It is not correct. You need to dispose objects that implement IDisposable. That is why they implement IDisposable - to specify the fact that they wrap (directly or indirectly) unmanaged resources.

这是不正确的。您需要处理实现IDisposable的对象。这就是为什么它们实现IDisposable——以指定它们封装(直接或间接)非托管资源的事实。

In this case, the unmanaged resource is a GDI handle, and if you fail to dispose them when you are actually done with them, you will leak those handles. Now these particular objects have finalizers that will cause the resources to be released when the GC kicks in, but you have no way of knowing when that will happen. It might be 10 seconds from now, it might be 10 days from now; if your application does not generate sufficient memory pressure to cause the GC to kick in and run the finalizers on those brushes/pens/fonts/etc., you can end up starving the OS of GDI resources before the GC ever realizes what's going on.

在本例中,非托管资源是一个GDI句柄,如果您在实际使用它们时未能处理它们,您将会泄漏这些句柄。现在这些特定的对象具有终结器,当GC启动时,这些终结器将导致资源被释放,但是您无法知道何时会发生这种情况。可能是10秒后,也可能是10天后;如果您的应用程序没有生成足够的内存压力,导致GC启动并在这些笔刷/钢笔/字体/等等上运行终结器。,在GC意识到发生了什么之前,您最终可能会耗尽GDI资源的OS。

Additionally, you have no guarantee that every unmanaged wrapper actually implements a finalizer. The .NET Framework itself is pretty consistent in the sense that classes implementing IDisposable implement it with the correct pattern, but it is completely possible for some other class to have a broken implementation that does not include a finalizer and therefore does not clean up properly unless Dispose is called explicitly on it. In general, the purpose of IDisposable is that you are not supposed to know or care about the specific implementation details; rather, if it's disposable, then you dispose of it, period.

此外,您不能保证每个非托管包装器实际上都实现了终结器。. net框架本身是相当一致的,类实现IDisposable实现它与正确的模式,但它是完全有可能一些其他类的实现,并不包括终结器,因此不正确清理除非处理被称为明确。一般来说,IDisposable的目的是你不应该知道或关心具体的实现细节;相反,如果它是一次性的,那么你就把它处理掉。

Moral of the story: Always dispose IDisposable objects. If your class "owns" objects that are IDisposable, then it should implement IDisposable itself.

故事的寓意:总是处理一次性物品。如果您的类“拥有”IDisposable对象,那么它应该实现IDisposable本身。

#2


9  

You need to dispose them.

你需要处理它们。

Managed object manage their memory by themselves. But memory isn't the only resource that an object uses. Dispose() is intended to release the other resources.

托管对象自己管理它们的内存。但是内存不是对象使用的唯一资源。Dispose()用于释放其他资源。

#3


5  

There is a marked irony in your approach. By pre-creating the pens/brushes, you are exactly creating the problem that Dispose() is trying to solve. Those GDI objects will be around longer, just like they would be when you don't call Dispose(). It is actually worse, they'll be around at least until the form is closed.

你的做法带有明显的讽刺意味。通过预创建钢笔/画笔,您正在创建Dispose()试图解决的问题。这些GDI对象的存在时间将会更长,就像您不调用Dispose()时一样。更糟糕的是,它们至少会一直存在直到表单关闭。

They are probably around long enough to get promoted to generation #2. The garbage collector doesn't do a gen#2 collection very often, it is now more important to call Dispose() on them. Do so by moving the Dispose() method of the form from the Designer.cs file to your form.cs file and add the Dispose calls.

它们可能存在的时间足够长,可以被提升到第2代。垃圾收集器不经常执行第2代收集,现在更重要的是对它们调用Dispose()。通过从设计器中移动表单的Dispose()方法来实现这一点。cs文件到您的表单。cs文件并添加配置调用。

But, do this the Right Way. Pens and brushes are very cheap objects. Create them when you need them, in the Paint event. And use the using statement so they'll get disposed right away. Use the Stopwatch class to re-assure yourself this doesn't actually cause any slowdown.

但是,用正确的方法。钢笔和刷子都是很便宜的东西。当你需要的时候,在绘制事件中创建它们。使用using语句,它们会被立即处理。使用秒表类来再次确保这不会导致任何减速。

#4


3  

I wrote a GDI+ diagramming component which used lots of pens and brushes. I created them and disposed them in the block of code that was doing the drawing and performance was never an issue. Better that then having a long lived handle hanging around in the OS IMHO.

我写了一个GDI+绘图组件,使用了很多笔刷。我创建了它们,并将它们放在正在绘制的代码块中,而性能从来都不是问题。更好的是,在操作系统IMHO上有一个长柄的手柄。

#5


2  

Have you profiled this to see if Creating & Disposing these objects really is a problem? I don't think it is.

你是否已经对这些对象进行了分析,以确定这些对象的创建和处理是否真的是一个问题?我不这么认为。

You make things a lot easier for yourself and certainly less error prone by just following the create-in-a-using-block pattern.

您可以让事情变得更简单,并且通过遵循“只使用一个块”的模式,当然也不会容易出错。

If you do want to create them once, then also implement IDisposable on your owning class and iterate the Dispose over your owned objects. No need for a destructor (finalizer).

如果您确实想要创建它们一次,那么也要在您的拥有类上实现IDisposable,并对您拥有的对象进行迭代。不需要破坏者(终结器)。

There is almost no cost on doing this to objects that don't actually need Dispose, but there is a big cost if you forget Dispose on an object that does need it.

对实际上不需要Dispose的对象执行此操作几乎没有成本,但是如果您忘记处理需要处理的对象,则会产生很大的成本。

#6


1  

No, IDisposable is for managed objects that use unmanaged resources. As a rule, you should always dispose of them when finished.

不,IDisposable是用于使用非托管资源的托管对象。通常,你应该在完成的时候处理掉它们。

#7


1  

You really need to look up the documentation for the brushes, pens etc.

你真的需要查阅笔刷、笔等的文档。

If they aren't using unmanaged resources, you may not have to call Dispose. But the using/Dispose pattern is sometimes "misused". As an example, consider the ASP.NET MVC framework. Here you can write something like:

如果它们不使用非托管资源,您可能不需要调用Dispose。但是使用/处理模式有时是“误用”的。以ASP为例。净MVC框架。你可以这样写:

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

When Html.BeginForm(...) is called, a FORM tag will be output. When the using-statement ends, Dispose will be called on the object returned from Html.BeginForm(...). Calling Dispose causes the end FORM tag to be rendered. In this way the compiler will actually enforce the pairing of FORM tags, so you won't forget the closing tag.

当Html.BeginForm(…)被调用时,将输出一个表单标记。当使用语句结束时,将对从Html.BeginForm(…)返回的对象调用Dispose。调用Dispose将导致呈现最终表单标记。通过这种方式,编译器将实际执行表单标记的配对,因此您不会忘记结束标记。

#8


1  

No, Pens and Brushes are not fully managed objects.

不,笔和笔刷不是完全管理的对象。

They contain a handle to an unmanaged resource, i.e. the corresponding GDI object in the underlying graphics system. (Not certain about the exact terminology here...)

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

If you don't dispose them, the handles will not be released until the objects are finalised by the garbage collector, and there is no guarantee that it will happen soon, or at all.

如果您不处理它们,那么在垃圾收集器完成对象之前,句柄不会被释放,而且也不能保证这种情况会很快发生,或者根本不会发生。

#9


1  

Others have alluded to "using" blocks for GDI objects - here's a code example:

还有一些人提到了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

Note that you can have as many "using" lines as you want for a single code block.

请注意,您可以使用您想要的单个代码块的“使用”行。

I think this is a nice, clean way to deal with Disposable objects.

我认为这是处理一次性物品的好方法。

#10


1  

No that is wrong. I agree with Aaronaught.

不,这是错误的。我同意Aaronaught。

In addition, Microsoft recommends, in a mid 2003 webcast that Don Box presented, that every .Net developer should dispose of their own objects, whether managed or unmanaged, as this improves code performance by anything upto 20%. If done right it can be a substantial performance improvement. So its a core skill that every .net developer needs to know and use.

此外,微软在2003年年中发布的网络广播中建议,每个。net开发人员都应该处理自己的对象,不管是托管的还是非托管的,因为这样可以提高20%的代码性能。如果做得对,这将是一个实质性的性能改进。因此,这是每个。net开发人员都需要了解和使用的核心技能。

#11


0  

Although you asked about pens and brushes, Font is a class with some odd quirks. In particular, if one creates a font for the purpose of setting a control's Font property, one remains responsible for disposing of that font--ownership does not transfer to the control--but that responsibility can be carried out by disposing of the font at any time--even as soon as the font is created, before assigning it to the control. It seems Font is a combination of a managed information object and an unmanaged GDI resource, and for some purposes only the former is needed. Weird design--Font should have been two classes.

虽然你问过钢笔和笔刷,字体是一个带有一些奇怪怪癖的类。特别是,如果一个人创建一个字体设置控件的字体属性的目的,一个是负责处理字体,不转移所有权的控制,但责任可以由处理字体在任何时候——甚至当创建字体,之前分配控制。字体似乎是托管信息对象和非托管GDI资源的组合,出于某些目的,只需要前者。奇怪的设计——字体应该有两个类。

#12


0  

see my answer here on a similar thread. it should address your question and explain the ramifications if you don't call Dispose.

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

What happens if I dont call Dispose on the Pen object

如果我不调用Dispose在笔对象上

#1


43  

It is not correct. You need to dispose objects that implement IDisposable. That is why they implement IDisposable - to specify the fact that they wrap (directly or indirectly) unmanaged resources.

这是不正确的。您需要处理实现IDisposable的对象。这就是为什么它们实现IDisposable——以指定它们封装(直接或间接)非托管资源的事实。

In this case, the unmanaged resource is a GDI handle, and if you fail to dispose them when you are actually done with them, you will leak those handles. Now these particular objects have finalizers that will cause the resources to be released when the GC kicks in, but you have no way of knowing when that will happen. It might be 10 seconds from now, it might be 10 days from now; if your application does not generate sufficient memory pressure to cause the GC to kick in and run the finalizers on those brushes/pens/fonts/etc., you can end up starving the OS of GDI resources before the GC ever realizes what's going on.

在本例中,非托管资源是一个GDI句柄,如果您在实际使用它们时未能处理它们,您将会泄漏这些句柄。现在这些特定的对象具有终结器,当GC启动时,这些终结器将导致资源被释放,但是您无法知道何时会发生这种情况。可能是10秒后,也可能是10天后;如果您的应用程序没有生成足够的内存压力,导致GC启动并在这些笔刷/钢笔/字体/等等上运行终结器。,在GC意识到发生了什么之前,您最终可能会耗尽GDI资源的OS。

Additionally, you have no guarantee that every unmanaged wrapper actually implements a finalizer. The .NET Framework itself is pretty consistent in the sense that classes implementing IDisposable implement it with the correct pattern, but it is completely possible for some other class to have a broken implementation that does not include a finalizer and therefore does not clean up properly unless Dispose is called explicitly on it. In general, the purpose of IDisposable is that you are not supposed to know or care about the specific implementation details; rather, if it's disposable, then you dispose of it, period.

此外,您不能保证每个非托管包装器实际上都实现了终结器。. net框架本身是相当一致的,类实现IDisposable实现它与正确的模式,但它是完全有可能一些其他类的实现,并不包括终结器,因此不正确清理除非处理被称为明确。一般来说,IDisposable的目的是你不应该知道或关心具体的实现细节;相反,如果它是一次性的,那么你就把它处理掉。

Moral of the story: Always dispose IDisposable objects. If your class "owns" objects that are IDisposable, then it should implement IDisposable itself.

故事的寓意:总是处理一次性物品。如果您的类“拥有”IDisposable对象,那么它应该实现IDisposable本身。

#2


9  

You need to dispose them.

你需要处理它们。

Managed object manage their memory by themselves. But memory isn't the only resource that an object uses. Dispose() is intended to release the other resources.

托管对象自己管理它们的内存。但是内存不是对象使用的唯一资源。Dispose()用于释放其他资源。

#3


5  

There is a marked irony in your approach. By pre-creating the pens/brushes, you are exactly creating the problem that Dispose() is trying to solve. Those GDI objects will be around longer, just like they would be when you don't call Dispose(). It is actually worse, they'll be around at least until the form is closed.

你的做法带有明显的讽刺意味。通过预创建钢笔/画笔,您正在创建Dispose()试图解决的问题。这些GDI对象的存在时间将会更长,就像您不调用Dispose()时一样。更糟糕的是,它们至少会一直存在直到表单关闭。

They are probably around long enough to get promoted to generation #2. The garbage collector doesn't do a gen#2 collection very often, it is now more important to call Dispose() on them. Do so by moving the Dispose() method of the form from the Designer.cs file to your form.cs file and add the Dispose calls.

它们可能存在的时间足够长,可以被提升到第2代。垃圾收集器不经常执行第2代收集,现在更重要的是对它们调用Dispose()。通过从设计器中移动表单的Dispose()方法来实现这一点。cs文件到您的表单。cs文件并添加配置调用。

But, do this the Right Way. Pens and brushes are very cheap objects. Create them when you need them, in the Paint event. And use the using statement so they'll get disposed right away. Use the Stopwatch class to re-assure yourself this doesn't actually cause any slowdown.

但是,用正确的方法。钢笔和刷子都是很便宜的东西。当你需要的时候,在绘制事件中创建它们。使用using语句,它们会被立即处理。使用秒表类来再次确保这不会导致任何减速。

#4


3  

I wrote a GDI+ diagramming component which used lots of pens and brushes. I created them and disposed them in the block of code that was doing the drawing and performance was never an issue. Better that then having a long lived handle hanging around in the OS IMHO.

我写了一个GDI+绘图组件,使用了很多笔刷。我创建了它们,并将它们放在正在绘制的代码块中,而性能从来都不是问题。更好的是,在操作系统IMHO上有一个长柄的手柄。

#5


2  

Have you profiled this to see if Creating & Disposing these objects really is a problem? I don't think it is.

你是否已经对这些对象进行了分析,以确定这些对象的创建和处理是否真的是一个问题?我不这么认为。

You make things a lot easier for yourself and certainly less error prone by just following the create-in-a-using-block pattern.

您可以让事情变得更简单,并且通过遵循“只使用一个块”的模式,当然也不会容易出错。

If you do want to create them once, then also implement IDisposable on your owning class and iterate the Dispose over your owned objects. No need for a destructor (finalizer).

如果您确实想要创建它们一次,那么也要在您的拥有类上实现IDisposable,并对您拥有的对象进行迭代。不需要破坏者(终结器)。

There is almost no cost on doing this to objects that don't actually need Dispose, but there is a big cost if you forget Dispose on an object that does need it.

对实际上不需要Dispose的对象执行此操作几乎没有成本,但是如果您忘记处理需要处理的对象,则会产生很大的成本。

#6


1  

No, IDisposable is for managed objects that use unmanaged resources. As a rule, you should always dispose of them when finished.

不,IDisposable是用于使用非托管资源的托管对象。通常,你应该在完成的时候处理掉它们。

#7


1  

You really need to look up the documentation for the brushes, pens etc.

你真的需要查阅笔刷、笔等的文档。

If they aren't using unmanaged resources, you may not have to call Dispose. But the using/Dispose pattern is sometimes "misused". As an example, consider the ASP.NET MVC framework. Here you can write something like:

如果它们不使用非托管资源,您可能不需要调用Dispose。但是使用/处理模式有时是“误用”的。以ASP为例。净MVC框架。你可以这样写:

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

When Html.BeginForm(...) is called, a FORM tag will be output. When the using-statement ends, Dispose will be called on the object returned from Html.BeginForm(...). Calling Dispose causes the end FORM tag to be rendered. In this way the compiler will actually enforce the pairing of FORM tags, so you won't forget the closing tag.

当Html.BeginForm(…)被调用时,将输出一个表单标记。当使用语句结束时,将对从Html.BeginForm(…)返回的对象调用Dispose。调用Dispose将导致呈现最终表单标记。通过这种方式,编译器将实际执行表单标记的配对,因此您不会忘记结束标记。

#8


1  

No, Pens and Brushes are not fully managed objects.

不,笔和笔刷不是完全管理的对象。

They contain a handle to an unmanaged resource, i.e. the corresponding GDI object in the underlying graphics system. (Not certain about the exact terminology here...)

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

If you don't dispose them, the handles will not be released until the objects are finalised by the garbage collector, and there is no guarantee that it will happen soon, or at all.

如果您不处理它们,那么在垃圾收集器完成对象之前,句柄不会被释放,而且也不能保证这种情况会很快发生,或者根本不会发生。

#9


1  

Others have alluded to "using" blocks for GDI objects - here's a code example:

还有一些人提到了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

Note that you can have as many "using" lines as you want for a single code block.

请注意,您可以使用您想要的单个代码块的“使用”行。

I think this is a nice, clean way to deal with Disposable objects.

我认为这是处理一次性物品的好方法。

#10


1  

No that is wrong. I agree with Aaronaught.

不,这是错误的。我同意Aaronaught。

In addition, Microsoft recommends, in a mid 2003 webcast that Don Box presented, that every .Net developer should dispose of their own objects, whether managed or unmanaged, as this improves code performance by anything upto 20%. If done right it can be a substantial performance improvement. So its a core skill that every .net developer needs to know and use.

此外,微软在2003年年中发布的网络广播中建议,每个。net开发人员都应该处理自己的对象,不管是托管的还是非托管的,因为这样可以提高20%的代码性能。如果做得对,这将是一个实质性的性能改进。因此,这是每个。net开发人员都需要了解和使用的核心技能。

#11


0  

Although you asked about pens and brushes, Font is a class with some odd quirks. In particular, if one creates a font for the purpose of setting a control's Font property, one remains responsible for disposing of that font--ownership does not transfer to the control--but that responsibility can be carried out by disposing of the font at any time--even as soon as the font is created, before assigning it to the control. It seems Font is a combination of a managed information object and an unmanaged GDI resource, and for some purposes only the former is needed. Weird design--Font should have been two classes.

虽然你问过钢笔和笔刷,字体是一个带有一些奇怪怪癖的类。特别是,如果一个人创建一个字体设置控件的字体属性的目的,一个是负责处理字体,不转移所有权的控制,但责任可以由处理字体在任何时候——甚至当创建字体,之前分配控制。字体似乎是托管信息对象和非托管GDI资源的组合,出于某些目的,只需要前者。奇怪的设计——字体应该有两个类。

#12


0  

see my answer here on a similar thread. it should address your question and explain the ramifications if you don't call Dispose.

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

What happens if I dont call Dispose on the Pen object

如果我不调用Dispose在笔对象上