技术开发 频道

.Net程序开发中一个较为隐蔽的GDI泄露探析

【IT168技术文档】最近一直在调试第三方委托开发的医疗输液系统(我接手时,代码已经完成,原则上我只修改接口部分以适应我们的硬件即可,不过调试过程中,该程序本身问题暴露不少),该系统用VB.net开发,该软件的图形界面是花费n多银子专门做的美工,大量的贴图,就是目前的主流PC机配置,也很难在调试模式下走顺溜。

问题出在两方面,第一、存在内存泄露(有时间我专门为此写篇文章),第二、存在GDI泄露。

 

最早的时候由于存在内存泄露问题,我一直以为windows弹出的“GDI一般性错误是由于内存泄露引起的,直到内存问题得以解决,程序还是运行一段时间就弹出类似错误。查了很多资料,发现windows任务管理器可以查看GDI是否泄露,如下图(在查看菜单,选定“选择列”对话框中gdi对象选项)

发现,该程序的GDI对象计数猛涨,由于没有很好的GDI检查工具和方法(如果这方面有高手,希望不吝指教),所以我对程序中大段大段涉及GDI的代码进行屏蔽,然后再检查是否GDI有泄露,n次重复后,功夫不负有心人,终于锁定罪魁祸首,相关代码如下:

Select Case (uPumpData.PumpName & "").Trim Case "******" IRBDetail.Icon = Icon.FromHandle(CType(ImgTabPage.Images(1), Bitmap).GetHicon) Case "XXXXXX" IRBDetail.Icon = Icon.FromHandle(CType(ImgTabPage.Images(0), Bitmap).GetHicon) Case Else IRBDetail.Icon = Nothing End Select 问题就出在 Icon.FromHandle(CType(ImgTabPage.Images(1), Bitmap).GetHicon)这句代码上,msdn在关键时刻不辱使命,一查结果真相大白: Icon.FromHandle 方法 从图标的指定 Windows 句柄 (HICON) 创建 GDI+ Icon。 命名空间:System.Drawing 程序集:System.Drawing(在 system.drawing.dll 中) Visual Basic(声明) Public Shared Function FromHandle (handle As IntPtr ) As Icon Visual Basic(用法) Dim handle As IntPtr Dim returnValue As Icon returnValue = Icon.FromHandle(handle) 参数 handle 图标的 Windows 句柄。 返回值 此方法创建的 Icon。 备注 使用此方法时,必须使用 Win32 API 中的 DestroyIcon 方法释放产生的图标以确保释放相应资源。 示例 下面的代码示例设计用于 Windows 窗体,它需要 PaintEventArgse(这是 Paint 事件处理程序的参数)。代码执行下列操作: · 创建一个 Bitmap。 · 将该对象绘制到屏幕。 · 获取 Bitmap 的图标句柄。 · 将窗体的 Form.Icon 属性设置为从该句柄创建的图标。 · 调用 Win32 API 函数 DestroyIcon 以释放资源。 <System.Runtime.InteropServices.DllImportAttribute("user32.dll")> _ Private Shared Function DestroyIcon(ByVal handle As IntPtr) As Boolean End Function Private Sub GetHicon_Example(ByVal e As PaintEventArgs) ' Create a Bitmap object from an image file. Dim myBitmap As New Bitmap("c:\FakePhoto.jpg") ' Draw myBitmap to the screen. e.Graphics.DrawImage(myBitmap, 0, 0) ' Get an Hicon for myBitmap. Dim HIcon As IntPtr = myBitmap.GetHicon() ' Create a new icon from the handle. Dim newIcon as Icon = System.Drawing.Icon.FromHandle(HIcon) ' Set the form Icon attribute to the new icon. Me.Icon = newIcon ' Destroy the icon, since the form creates its ' own copy of the icon. DestroyIcon(newIcon.Handle) End Sub 注意,备注很关键:要用API DestroyIcon释放相关对象。 我声明了一个API函数: Public Declare Function DestroyIcon Lib "user32" Alias "DestroyIcon" (ByVal hIcon As Integer) As Integer 在IRBDetail.Icon的属性代码中添加了如下代码,问题立马解决(当然类销毁的代码中,m_Icon也要释放一下)。 Public Property Icon() As Icon Get Return m_Icon End Get Set(ByVal Value As Icon) '叶帆 2007.08.31 If Not IsNothing(m_Icon) Then DestroyIcon(m_Icon.Handle) m_Icon.Dispose() m_Icon = Nothing End If m_Icon = Value Me.Invalidate() End Set End Property

 

千里之堤溃于蚁穴,几万行的代码,就坏在这一点上,实在值得人警惕!

 

 

原文地址

 

 

 

 

 

 

0
相关文章