处理SolidBrush和Pen是否重要?

Joe*_*Joe 17 .net idisposable winforms

我最近遇到了CodeProject上的VerticalLabel控件.

我注意到OnPaint方法创建但不处理Pen和SolidBrush对象.

这是否重要,如果是这样,我怎样才能证明它可能导致的任何问题?

编辑

这不是关于IDisposable模式的一般问题.我知道调用者通常应该在任何实现IDisposable的类上调用Dispose.

我想知道的是,当GDI +对象没有按照上面的例子那样处理时,可以预期会出现什么问题(如果有的话).很明显,在链接的示例中,在垃圾收集器启动之前可能会多次调用OnPaint,因此可能会耗尽句柄.

但是我怀疑GDI +在某些情况下内部重用句柄(例如,如果你使用Pens类中特定颜色的笔,它会被缓存并重用).

我想要了解的是,链接示例中的代码是否能够在忽略调用Dispose的情况下逃脱.

如果没有,看一个样本,证明它可能导致什么问题.

我应该补充一点,我经常(包括MSDN上的OnPaint文档)看到WinForms代码示例未能处理GDI +对象.

Kon*_*man 5

当然这很重要.在不再需要时,必须处理实现IDisposable的所有类实例.当类使用非托管资源(即.NET Framework未处理的操作系统资源)时,类被定义为IDisposable.

如果你没有手动处理对象,那么在垃圾收集器调用对象终结器之前不会释放这些非托管资源(这只有在类正确实现了Dispose模式时才会发生),这可能会很晚,因为垃圾收集器仅在检测到实际内存不足时才运行.因此,在不处理对象时,您将保留其他应用程序可能使用的操作系统资源.

关于这个主题的讨论可以在这里找到:http://agilology.blogspot.com/2009/01/why-dispose-is-necessary-and-other.html

  • 我的问题不是一般的IDisposable模式,我理解它的用途以及调用者通常应该调用Dispose的原因.请参阅编辑问题. (5认同)

wag*_*ghe 5

FWIW,在 GDI 中有“库存”对象。当您创建一个股票对象时,您没有删除它,因为它是由操作系统“拥有”的。

您可能已经了解库存对象,但这里有一个详细介绍的链接

不知道GDI+中有没有类似的“库存”对象。我刚刚进行了简短的搜索,但没有找到任何对此类的引用。

作为测试,我编写了一个带有计时器回调的小型 WinForms 程序(设置为每 10 毫秒触发一次),如下所示:

private void timer1_Tick(object sender, EventArgs e)
{
  byte r = (byte)rnd.Next(0, 256);
  byte g = (byte)rnd.Next(0, 256);
  byte b = (byte)rnd.Next(0, 256);

  System.Drawing.SolidBrush sb = new SolidBrush(Color.FromArgb(0,r,g,b));
}
Run Code Online (Sandbox Code Playgroud)

如果我让它运行,它会慢慢消耗内存。通过观察 TaskManager(不是衡量它的最准确的方法),每次任务管理器更新(在最高更新率)时,内存使用量往往会增加(在我的机器上,使用 .NET 4.0 VS2010,Release 构建)大约 20k 字节。如果我在画笔上调用 Dispose,则每次任务管理器更新时内存使用量会增加约 8k。

几乎不是一个明确的测试,但如果不处理 SolidBrush,它似乎表明随着时间的推移内存使用量会增加。有趣的是,在测试运行时,我的 Handles 和 GDI Objects 都没有增加(在任何一种情况下)。根据过去泄露 GDI 资源的经验,我预计 GDI 对象可能会增长,尤其是在非 Dispose 情况下。

无论如何,这也许是有用的,也许不是。


Chr*_*isF 1

只要对象没有被其他任何对象引用,它们就应该在超出范围后由垃圾收集进行处理。

演示这种情况是否发生(无需更改任何代码)的最简单方法是在窗体上使用大量此类控件,并查看应用程序使用的内存是否持续增长或保持稳定。