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

news/2024/6/17 23:14:49
 

最近一直在调试第三方委托开发的医疗输液系统(我接手时,代码已经完成,原则上我只修改接口部分以适应我们的硬件即可,不过调试过程中,该程序本身问题暴露不少),该系统用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 以释放资源。

_

    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

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





http://www.niftyadmin.cn/n/3655826.html

相关文章

js --- 图的深度广度优先遍历

深度优先遍算法口诀 访问根节点对根节点的没有访问过的降临节点进行深度优先遍历 const graph {0:[1,2],1:[2],2:[0,3],3:[3] } const visited new Set() const dfs (n) >{console.log(n)visited.add(n)graph[n].forEach(c > {if (!visited.has(c)){dfs(c)}}); } dfs…

西门子Prodave5.5使用说明及VC示例

西门子PLC的通信协议主要是PPI、MPI、Profibus、CP243/CP343/CP443 网络协议,prodave是早期完成的程序接口,除了网络协议外其它的主要协议都支持,SoftNet是西门子最新推出的通信协议接口,稳定,并且大而全,目…

2020-12-18 js 实现堆

堆是什么? 堆是一种特殊的完全二叉树所有的节点都大于等于(最大堆)或小于等于(最小堆)它的子节点。 js 中的堆 js 中通常用数组表示堆左侧子节点的位置是 2 * index 1右侧子节点的位置是2* index 2父节点位置是&am…

VB实现SHELL扩展之接口参数获取失败探析

前几天有位网友问我用VB实现SHELL扩展的问题,这个问题比较有意思,虽然VB较少使用了,但是用VB开发COM组件还是比较方便的(前几天用EVC开发COM组件,相比起来,用VB还是比较幸福的),所以…

js 排序学习

冒泡排序 Array.prototype.bubbleSort function() {// console.log(this)for (let i 0; i < this.length - 1; i) {for(let j 0;j<this.length -1 - i; j1){ // -1 可以用j1来获取 - i是为了缩小循环节省时间if(this[j] > this[j1]){const temp this[j] // …

16进制字符串转数字(C/C++,VB/VB.net,C#)

这个问题看是很简单&#xff0c;但是在不同语言中实现的方式却千差万别&#xff0c;如果不知道方法&#xff0c;还真是麻烦&#xff0c;我就是在C#中遇到该问题&#xff0c;让我费了很大的周折&#xff0c;才在msdn查到。一、16进制字符串转数字1、C/CI、最简单的办法&#xff…

面试题 ---快速排序的空间复杂度是多少?时间复杂度的最好最坏的情况是多少,有哪些优化方案?

Array.prototype.quickSort function() {const rec (arr) >{if(arr.length 1){return arr}// 分别存放 前后的数组const left []const right []// 设置一个基准const mid arr[0]//进行分区for(let i 1; i<arr.length; i1){if(arr[i] < mid){left.push(arr[i])}el…

如何加速XML反序列化(精简框架集2.0SP1,WinCE4.2) -- 寻求微软技术支持记

其实这个问题在2007/3/13 就提交到了微软技术支持&#xff0c;但直到今天&#xff0c;对这个问题还没有一个完美的结果&#xff08;他们最好的建议就是&#xff0c;自己解析XML文件&#xff09;&#xff0c;只好请求微软的技术支持把这个问题close掉。问题的关键在于&#xff1…