c# - GDI+ 对象生命周期的最佳策略?

标签 c# winforms gdi+ idisposable

在我们的应用程序中,我们有一些经常在许多不同上下文中使用的 GDI+ 对象。这包括一些 FontSolidBrush(White、Black...)、一些 Pen...

到目前为止,对于这些对象,我们的策略是通过广泛可见的静态只读字段来保存它们。这避免了数百万次创建/处置它们。当然,我们处理了对这些对象的线程安全访问(它们基本上只是从 UI 线程访问)。

这些 GDI+ 对象中只有少数会在应用程序的生命周期内保留,比如 200 个。其他 GDI+ 对象(生命周期较短的对象)都将尽快处理掉。但我们有时会遇到意外的 GDI+ 资源中断异常,希望这种情况很少发生。

我想知道这些异常是否可能来自持有的这几个 GDI+ 对象,以及创建/处置大量短生命周期 GDI+ 对象是否是更明智的策略。有没有人对这两种策略有实际经验和相关结论?

最佳答案

缓存 System.Drawing 对象是一个错误。它们的制造成本非常低,但保存起来却非常昂贵。它们被分配在一个特殊的堆上,桌面上的所有进程都需要共享。堆大小限制为 65535 个对象。创建像画笔或钢笔这样的对象大约需要一微秒,与您使用它们执行操作的成本相比微不足道。唯一昂贵的绘图对象是字体。创建一个涉及字体映射器占用的大量开销。但这已经被 .NET 解决了,它缓存了它们。

除了不必要地占用堆之外,编程风格是危险的。盲目地应用 using 语句太容易忘记了。这肯定会给您带来麻烦,您依赖终结器线程再次释放它们。如果程序涉及大量繁重的绘制但没有足够的对象分配来触发 GC,那么您耗尽 GDI 对象的配额。默认情况下,一个进程有 10,000 个对象。这将使您的程序崩溃。请注意,System.Drawing 类包装器的大小不足以自行触发 GC,其中 10000 个包装器不足以让终结器运行并再次释放句柄。

这个问题很容易诊断,你可以使用任务管理器。使用 View + Select Columns 并勾选“GDI Objects”。不妨勾选“用户对象”,这是另一个非常容易泄露的对象。使用过程时,请注意显示的过程计数。稳步攀升的数字意味着厄运。

关于c# - GDI+ 对象生命周期的最佳策略?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22814259/

相关文章:

C# 使用 bool 函数将列表拆分为两个列表

c# - 反序列化时仅用于未设置属性的默认值

winapi - 使用 GDI+ 的 Windows 初始屏幕

c# - WPF MultiBinding 到 Model.ChildProperty 不起作用?

c# - Kong Solutions 拖放以对列表进行排序,从列表中删除项目

c# - 只读与静态只读说明

c# - DataGridViewCombBoxColumn 单元格值和不同的下拉列表

c# - 向 TextBox 添加静态文本

.net - byte[] 到 XImage 失败并出现一般 GDI+ 错误

c# - 如何使用 GDI+(C#、WinForms)绘制带有路径渐变的圆弧