GDI对象计数跨越10k

MrC*_*lan 0 .net windows user-interface gdi winforms

我们在C#中有一个.net应用程序,它允许域中的用户映射到另一个域中的用户/角色.

在属性映射面板(它只是在主窗体上显示为对话框的简单窗体)中,有两个列表视图 - 1个用于源域,另一个用于所有先前选择的目标域.列表视图中填充了用户和组 - 每个用户/组一行.我们每行都有一个图标来区分用户和组.

一切都很好,直到最近我们的一个客户遇到了没有的情况.由我们的应用程序创建的GDI句柄超过10k - 这是可以由Windows系统上的进程创建的句柄的可能数量的上限.所以,现在我们正在考虑使用哪些方法来减少创建的句柄数量.以下是我们想要确保的几个问题.其中哪一个创建了一个新句柄(我们怀疑所有这些句柄):

1)

this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 14F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(177)));
Run Code Online (Sandbox Code Playgroud)

2)

this.pictureBox1.Image = ((System.Drawing.Image)(resources.GetObject("pictureBox1.Image")));
Run Code Online (Sandbox Code Playgroud)

3)

this.label2.Text = resources.GetString("label2.Text");
Run Code Online (Sandbox Code Playgroud)

请不要关心问题的格式,如果相关结论需要进一步的信息,请告诉我.

我们可以做些什么来减少号码.把手创建?避免这种情况的正确方法是什么?可以明确杀死句柄以减少计数(只是说)?任何建议或要照顾的事情都表示赞赏.谢谢.

另外,我们有这行代码:

this.imageList1.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageList1.ImageStream")));
Run Code Online (Sandbox Code Playgroud)

那么,我们如何释放DC和Bitmaps处理?

GDIView的屏幕截图

Han*_*ant 6

是的,您的程序正在泄漏System.Drawing对象."Bitmap"显示的每个计数都是程序中的Image或Bitmap对象,"DC"(设备上下文)的每一个计数都是程序中的Graphics对象.

这些类实现了IDisposable,当你不再使用它们时,你应该调用它们的Dispose()方法.忘记这样做是一个非常普遍的疏忽.由于DC计数与Bitmap计数几乎相同,因此您可以很好地了解从哪里开始查找缺少的Dispose()调用或使用语句,Bitmap和Graphics对象应该非常接近.

还有一个强烈暗示,你的程序中的终结器线程运行频率不足以让你免于麻烦.对此的简单解释是,您只是没有分配足够的对象来触发垃圾回收.这并不完全不寻常,Graphics和Bitmap类是非常小的类,它们本身永远不足以触发GC.因此,如果您的程序很重,但数据量不大,或者数据是由非托管代码(如System.DirectoryServices中的类)存储的,那么GC不会经常启动.

一个世界末日的场景是终结器线程被破坏并且已经死锁.没有非托管调试器很难注意到这一点,除了你注意到这种确切的资源泄漏.一个容易被忽视的怪癖,当你关闭主窗口时程序停止运行需要两秒钟.终结器线程中的死锁通常是由线程问题引起的,特别是对于COM对象.就像System.DirectoryServices中使用的那种.您需要启用非托管调试并启用Microsoft Symbol服务器以使其在堆栈跟踪中看到死锁.

希望不是这样.通过运行Perfmon.exe来查看GC正在做什么.右键单击该图并为您的程序添加".NET CLR Memory"类别中的"#Gen 0 Collections".期望它不会以稳定的剪辑增加.

如果您找不到该错误或它位于您无法修复的代码中,那么您可能需要帮助并强制垃圾收集器运行.您可以使用Timer,并在Tick事件处理程序中调用GC.Collect().或者最好在代码中的任何其他位置,您可以合理地放置一个代表泄漏的图形/位图对象数量的计数器.