使用GDIView工具排查GDI对象泄漏案例的若干细节总结

news2024/9/20 14:52:25

目录

1、查看任务管理器,发现程序中有明显的GDI对象泄漏

2、使用GDIView工具查看发生泄漏的是哪一种GDI对象

3、尝试找到复现问题的方法,缩小排查范围,逐步地找到GDI对象的泄漏点

4、本案例中的相关细节点的思考与总结(有价值的细节点)

4.1、UI界面无法显示的原因分析

4.2、使用GDIView工具查看泄漏的对象,并尝试找到问题复现的办法,缩小代码排查的范围

4.3、如果还是无法定位问题,可以尝试使用历史版本比对法等其他方法来辅助排查

5、最后


C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125529931C/C++实战进阶(已更新到400多篇,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_11931267.htmlVC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/124272585C++ 软件开发从入门到精通(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_12695902.htmlC++软件分析工具从入门到精通案例集锦(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/131405795开源组件及数据库技术(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_12458859.html网络编程与网络问题分享(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_2276111.html       最近项目中又遇到了一个GDI对象泄漏的问题,这个问题虽然不难排查,但其中涉及的部分细节点很有价值,所以今天依托这个案例再写一篇文章,详细讲述这个问题的完整排查过程,并对案例中涉及的若干细节点进行详细的总结,以供大家借鉴或参考。

1、查看任务管理器,发现程序中有明显的GDI对象泄漏

       最近测试同事在拷机测试一段时间后,软件出现了问题,很多界面显示不出来了,双击托盘图标后主界面也显示不出来了。

       打开任务管理器,查看进程的资源占用,内存占用是正常的,看到进程占用的GDI对象总数是有问题的,居然达到9000多个:

应该是程序中发生GDI对象泄漏了。进程的GDI上限是1万个,当GDI对象总数达到或接近1万时,用于绘图的GDI函数就会出异常,绘图失败,窗口绘制失败就会显示异常。所以当前窗口显示不出来,所以当前的这个窗口显示不出来的问题,肯定是GDI对象泄漏导致的。光知道程序中有GDI对象泄漏是不够的,还要使用GDIView工具查看具体是哪一类GDI对象有泄漏,这样才有明确的排查目标。

       关于Windows程序进程的GDI对象的上限值的详细说明,可以查看我的文章:

从注册表看Windows系统进程GD对象及进程句柄数上限icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/139565038       此外,注意一下,Windows任务管理器的进程列表中默认是不显示GDI对象的,可以右键点击进程列表的列表头,在弹出的右键菜单中点击“选择列”:

然后在弹出的窗口中找到GDI对象选项:

勾选上即可看到进程的GDI对象总数。

正常情况下,进程的GDI对象总数最多只会有上千个左右,如果有好几千,一般就能确定程序中发生GDI对象泄漏了。

2、使用GDIView工具查看发生泄漏的是哪一种GDI对象

       于是将查看GDI对象占用的工具GDIView发给测试同事,打开后看到DC对象占的特别高,竟然高达7000多个:

应该是DC对象发生泄漏了。DC对象发生泄漏可能存在两个场景:

1)调用GetDC后,没有调用ReleaseDC去释放;
2)调用CreateCompatibleDC后,没有调用DeleteDC去释放。

       一般GDI对象泄漏都发生在处理窗口绘制的UI模块中,但也少部分模块会涉及,比如处理桌面共享图像采集的音视频模块,音视频模块的桌面图像采集、视频图像绘制可能会使用到GDI函数进行绘图,会使用到GDI对象。

       使用GDIView工具只能确定是DC对象发生了泄漏,但看不到其他信息,要找出DC对象的泄漏点,只能去查看源码。但程序的模块太多,还需要尝试复现问题,找到问题的复现规律,根据复现问题的相关操作,缩小排查的范围,逐步地锁定泄漏点


       在这里,给大家重点推荐一下我的几个热门畅销专栏,欢迎订阅:(博客主页还有其他专栏,可以去查看)

专栏1:该精品技术专栏的订阅量已达到510多个,专栏中包含大量项目实战分析案例,有很强的实战参考价值,广受好评!专栏文章持续更新中,预计更新到200篇以上!欢迎订阅!)

C++软件调试与异常排查从入门到精通系列文章汇总icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125529931

本专栏根据多年C++软件异常排查的项目实践,系统地总结了引发C++软件异常的常见原因以及排查C++软件异常的常用思路与方法,详细讲述了C++软件的调试方法与手段,以图文并茂的方式给出具体的项目问题实战分析实例(很有实战参考价值),带领大家逐步掌握C++软件调试与异常排查的相关技术,适合基础进阶和想做技术提升的相关C++开发人员!

考察一个开发人员的水平,一是看其编码及设计能力,二是要看其软件调试能力!所以软件调试能力(排查软件异常的能力)很重要,必须重视起来!能解决一般人解决不了的问题,既能提升个人能力及价值,也能体现对团队及公司的贡献!

专栏中的文章都是通过项目实战总结出来的,包含大量项目问题实战分析案例,有很强的实战参考价值!专栏文章还在持续更新中,预计文章篇数能更新到200篇以上!

专栏2:  

C++常用软件分析工具从入门到精通案例集锦汇总(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/131405795

常用的C++软件辅助分析工具有SPY++、PE工具、Dependency Walker、GDIView、Process Explorer、Process Monitor、API Monitor、Clumsy、Windbg、IDA Pro等,本专栏详细介绍如何使用这些工具去巧妙地分析和解决日常工作中遇到的问题,很有实战参考价值!

专栏3:(本专栏涵盖了C++多方面的内容,是当前重点打造的专栏,专栏文章已经更新到400多篇,持续更新中...)

C/C++实战进阶(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_11931267.html

以多年的开发实战为基础,总结并讲解一些的C/C++基础与项目实战进阶内容,以图文并茂的方式对相关知识点进行详细地展开与阐述!专栏涉及了C/C++领域多个方面的内容,包括C++基础及编程要点(模版泛型编程、STL容器及算法函数的使用等)、数据结构与算法、C++11及以上新特性(不仅看开源代码会用到,日常编码中也会用到部分新特性,面试时也会涉及到)、常用C++开源库的介绍与使用、代码分享(调用系统API、使用开源库)、常用编程技术(动态库、多线程、多进程、数据库及网络编程等)、软件UI编程(Win32/duilib/QT/MFC)、C++软件调试技术(排查软件异常的手段与方法、分析C++软件异常的基础知识、常用软件分析工具使用、实战问题分析案例等)、设计模式、网络基础知识与网络问题分析进阶内容等。

专栏4:   

VC++常用功能开发汇总(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/124272585

将10多年C++开发实践中常用的功能,以高质量的代码展现出来。这些常用的高质量规范代码,可以直接拿到项目中使用,能有效地解决软件开发过程中遇到的问题。

专栏5: 

C++ 软件开发从入门到精通(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_12695902.html

根据多年C++软件开发实践,详细地总结了C/C++软件开发相关技术实现细节,分享了大量的实战案例,很有实战参考价值。


3、尝试找到复现问题的方法,缩小排查范围,逐步地找到GDI对象的泄漏点

       于是让测试同事能否找到复现的规律,在复现的过程中查看GDIView中DC对象的变化,看看是什么操作引发的GDI对象泄漏。测试同事也确实有一套,很快找到了复现规律,将视频窗口全屏后发起桌面共享,然后观察GDIView中当前进程的DC对象数目在快速的上升。

       首先是从UI模块查起,搜索调用GetDC和CreateCompatibleDC的代码,看下来发现没有明显的问题。

       本来想在我的开发机器上复现,如果复现了,也方便我们开发人员自行排查,但一直复现不了。当前出问题的机器是微软Surface平板电脑,这个平板电脑屏幕分辨率比较大,但屏幕的物理尺寸比较小,如果系统按100%先是,桌面图标和软件界面会显示的特别小,根本没法使用,必须调整系统的显示比例才能正常使用,比如可以调整到200%:

所以怀疑当前这个问题,可能和系统设置的比例有关系,于是手动将我们用的PC系统的显示比例调整到非100%。但调整后还是没有复现问题,所以可能和显示比例没有直接的关系,可能与设备有关,只能在微软的Surface平板上才能复现问题。

       既然UI模块没有找到明显的问题,那结合发送桌面共享时才有明显泄漏的现象,可能是负责桌面图像采集的音视频模块的代码中有泄漏。于是找到维护该模块的音视频开发组的同事,让他重点看看发送共享时桌面图像采集的代码,看看有没有使用到DC对象,是否存在DC对象没有释放的问题。

       后来考虑到音视频开发组的同事对UI编程细节不了解,直接去和他们一起去查看代码,以快速排查并确定问题。于是和同事一起去查采集桌面图像的代码,果然找到了问题,先是调用GetDC接口获取桌面窗口的DC:

但在使用完该DC对象之后,在当前函数的结尾处,并没有调用ReleaseDC去释放,所以产生了DC对象泄漏。

       在上述问题代码中,在函数结尾处居然使用ReleaseDC去释放一个调用CreateCompatibleDC接口创建的DC(m_hShowMemDC)

不去释放GetDC获取的DC(hDesktopDC)。应该还是音频开发组的同事对GDI UI界面编程不熟悉导致的,调用CreateCompatibleDC创建的DC对象,使用完成后,应该使用DeleteDC去释放;使用GetDC获取的DC,使用完成后,应该使用ReleaseDC去释放。

有些人可能会有误解,可能会觉得,使用CreateCompatibleDC创建的DC才需要去释放,使用GetDC获取的DC是不需要释放的。

4、本案例中的相关细节点的思考与总结(有价值的细节点)

       这个问题排查起来虽然不复杂,但其中涉及到的一些细节点,很有价值,在这里给大家详细总结一下。

4.1、UI界面无法显示的原因分析

       如果UI界面显示不出来,可能是以下原因导致的:

1)资源占用过多

       当内存或CPU资源占用过多,软件出现明显的卡顿。之前在微软Surface平板上遇到过,因为代码中在持续不断接收音视频数据,在不断的解码播放,占用了大量CPU资源,导致机器发热厉害,而Surface平板散热不好,CPU会降低频率,这样会占用更多的CPU,直接导致系统卡顿,软件也跟着异常卡顿。


2)UI线程堵塞卡死

       要看处理窗口事务的UI线程是否发生卡死堵塞,比如调用底层的接口一直没有返回,卡在WaitForSingleObject接口上,这是多线程死锁导致的。因为UI线程卡死了,点击窗口没法应了,本来要显示出来的窗口也显示不出来了。


3)GDI对象泄漏

       程序运行过程中有持续的GDI对象泄漏,当进程的GDI对象接近或达到1万个,负责窗口绘制的GDI函数会调用失败,窗口绘制不出来,导致窗口无法显示。本案例中的问题,就是这个原因导致的。

上述问题场景,我们在项目中都遇到过,而且不止一次遇到过! 

4.2、使用GDIView工具查看泄漏的对象,并尝试找到问题复现的办法,缩小代码排查的范围

       使用GDIView工具查看具体是哪个GDI对象发生了泄漏。确定泄漏对象之后,需要去查看代码去排查GDI对象的泄漏点。但软件的模块多,代码量大,不好漫无目标地排查。需要尝试去找到复现问题的办法,根据复现问题的操作步骤和场景,猜测问题可能出在哪些代码块中,即缩小代码排查的范围本文中的案例,也正是这么做的,有效地缩小了排查范围,快速地找到GDI对象的泄漏点。

4.3、如果还是无法定位问题,可以尝试使用历史版本比对法等其他方法来辅助排查

       如果上述方法很难查出问题,就可以尝试其他方法来辅助排查。如果当前的问题是最近才出现的或者最近几个月才出现的(如果时间过长,用历史版本比对法会比较费劲),可以使用历史版本比对法来辅助排查。

       我之前就写过两篇使用历史版本比对法排查GDI对象泄漏的案例,有一定的参考价值:
使用GDIView工具排查GDI对象泄漏问题(常用分析工具)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125399896使用GDIView工具排查GDI对象泄漏导致C++程序UI界面绘制异常的问题icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/140731065       历史版本比对法,就是找出第一次出现问题的那个时间点,基本上问题就是前一天提交的代码或者底层新发布的库导致的,然后在svn或git上查看前一天的修改记录,就能快速地找到问题了。 

       但历史版本比对法,依赖一套完备的版本自动化编译系统,我以前多次提到过。比如我们的版本自动化编译系统,编译版本的机器会每天凌晨通过svn或git将代码和库都更新成最新的,然后发起编译,生成版本(生成安装包或者升级包),然后自动将版本拷贝到文件服务器上供大家使用。这样只要代码有修改或者有库发布,在文件服务器上都会生成对应的版本,如下所示:

这样我们就好执行历史版本比对法了,就是用二分法安装不同时间点的版本,看看从哪天开始出现内存泄漏的,然后查看前一天svn或git上的修改记录就能快速找到方向和线索了。 

      历史版本比对法,虽然执行起来比较笨拙,但确实很好用,也很实用,我们在项目中多次使用过,屡试不爽啊!

5、最后

       案例本身可能比较简单,排查起来也很快,但案例中所涉及到的若干细节点可能很有价值,我们在问题复盘时要积极的思考与总结,也可以将之前遇到的一些问题及场景串联,进行归纳整理(多向自己提问,多问问自己为什么,要思维扩散,要联想串联)。有了这些思考和总结之后,下次在遇到类似问题时,就会有明确的排查思路和手段,能有效地提高问题排查的效率,能快速的定位问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2072600.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

httpClient与openfeign

目录 介绍 maven坐标 发送请求步骤 发送get请求 ​发送post请求 介绍 是一个客户端编程的工具包&#xff0c;也就是在java程序中&#xff0c;可以构造http请求并且发送请求 maven坐标 httpclient <dependency> <groupId>org.apache.httpcomponents</g…

【Kotlin设计模式】建造者模式在Android中的应用

前言 建造者模式&#xff08;Builder Pattern&#xff09;是一种创建型设计模式&#xff0c;一步一步地构建一个复杂对象的不同部分&#xff0c;而不是直接创建该对象的实例。建造者模式的核心思想是将对象的构建过程与其表示分离&#xff0c;使得同样的构建过程可以创建不同的…

如何使用ssm实现基于ssm的疫情物质管理系统

TOC ssm170基于ssm的疫情物质管理系统jsp 第一章 绪论 1.1 研究背景 时代总是在进步的&#xff0c;自从进入了信息时代&#xff0c;面对大量的不同种类的数据&#xff0c;仅仅依靠有限的人力去处理&#xff0c;显然是不行的&#xff0c;毕竟人工处理大量的数据会耗费较长时…

git提交项目,报403无权限

这个在公司内网git上提交项目时&#xff0c;使用的是刚分配到的账号和密码。创建完组和项目后一切准备完毕了&#xff0c;但是在提交时缺出了乌龙&#xff0c;报403&#xff0c;上面一堆英文&#xff0c;大致的意思是说我没有上传本项目的权限&#xff0c;报错信息如下图所示&a…

5.1二叉树——基本概念梳理

本篇博客梳理二叉树相关的基本概念 一、树的概念与结构 1&#xff0e;树是递归定义的 树根N棵子树&#xff0c;每棵子树也可按照相同方式拆分 注意&#xff1a;子树之间不能有交集&#xff0c;否则变成图&#xff08;是另一种数据结构&#xff09; 2&#xff0e;树的相关概…

Linux进程信号——信号的概念与产生

文章目录 信号及其产生与发送什么是Linux信号信号的产生终端按键系统调用软件条件硬件条件 核心转储存储临时信号 信号及其产生与发送 我们从生活中理解信号&#xff0c;例如各种指示灯&#xff0c;红绿灯之类的&#xff0c;我们能认识红绿灯是因为每一种不同的情况在我们大脑…

Apache Doris 跨集群数据同步 CCR 全面介绍

CCR 概述 CCR&#xff08;Cross Cluster Replication&#xff09;也就是跨集群数据复制&#xff0c;能够在库/表级别将源集群的数据变更同步到目标集群&#xff0c;可用于提升在线服务的数据可用性、隔离在离线负载、建设两地三中心等。 CCR 通常被用于容灾备份、读写分离、集…

末代皇帝Intel核显黑苹果,NUC10的性能到底有多强

末代皇帝Intel核显黑苹果&#xff0c;NUC10的性能到底有多强 一、可以核显的Intel iGPU有哪些 核显是一个伟大的产物&#xff0c;它可以在我们没有多余的钱去买多余的显卡的时候排上用场&#xff0c;特别是在mini小主机的市场上&#xff0c;核显就显得尤为重要的&#xff0c;…

图形化的Agent工具

1 图形化 Agent 工具 1.1 核心组件 机器人 Bot&#xff1a;一个 AI 应用&#xff0c;或称为 Agent知识库&#xff1a;上传个人数据&#xff0c;机器人可根据其内容进行回复工作流&#xff1a;将大问题拆解成多个小问题&#xff0c;通过路径实现&#xff0c;路径上的每个节点完…

tomcat实战演练

一.tomcat介绍 Tomcat 服务器是一个免费的开放源代码的 Web 应用服务器&#xff0c;属于轻量级应用服务器&#xff0c;在中小型系统和并发访问用户不是很多的场合下被普遍使用&#xff0c; Tomcat 具有处理 HTML 页面的功能&#xff0c;它还是一个 Servlet 和 JSP容器。Tomc…

Python优化算法13——飞蛾扑火优化算法(MFO)

科研里面优化算法都用的多&#xff0c;尤其是各种动物园里面的智能仿生优化算法&#xff0c;但是目前都是MATLAB的代码多&#xff0c;python几乎没有什么包&#xff0c;这次把优化算法系列的代码都从底层手写开始。 需要看以前的优化算法文章可以参考&#xff1a;Python优化算…

三种插入排序详解和代码实现(直接插入排序、折半插入排序和希尔排序)

目录 基本思想直接插入排序排序方法代码实现复杂度分析 折半插入排序排序方法代码实现复杂度分析 希尔排序排序方法代码实现复杂度分析最佳情况平均情况最坏情况增量序列的影响 基本思想 插入排序的基本思想是&#xff1a;每一趟将一个待排序的元素按照其关键字的大小插入到已经…

Hadoop 分布式集群搭建

HDFS分布式集群搭建 一、部署规划1.1 进程规划1.2 软件规划1.3 用户规划1.4 目录规划 二、 搭建HDFS 分布式集群2.1 HDFS 集群配置2.1.1 下载安装 Hadoop2.1.2 修改 hadoop-env.sh 配置文件2.1.3 修改 core-site.xml 配置文件2.1.4 修改 hdfs-site.xml 配置文件2.1.5 修改 slav…

力扣刷题(1)

两数之和 两数之和-力扣 思路&#xff1a; 动态开辟一个数组&#xff0c;用来存放下标&#xff1b;两个for循环嵌套来判断&#xff0c;数组中的两个数相加是否与target相等若相等&#xff0c;则将 * returnSize赋值为2&#xff0c;表示数组中两个数&#xff0c;并将arr数组…

数学建模之数据分析【九】:数据清理总结

文章目录 一、什么是数据清理二、为什么数据清理很重要三、执行数据清洁的步骤四、如何执行数据清理五、数据清理的Python库实现5.1 数据检查与探索5.2 使用df.info()检查数据信息5.3 检查分类和数字列5.4 检查分类列中唯一值的总数5.5 执行数据清理的步骤5.5.1 删除所有上述不…

真的爽到了!Coze的黑神话 “循环“ 闪亮登场,啥都能循环,让你一次通关!

心心念念了很久&#xff0c;Coze工作流终于支持循环操作啦&#xff0c;泪奔~~ 看&#xff0c;就在工作流节点的“选择器”和“意图识别”当中偷偷摸摸地多了一个“循环” 这玩意可比批处理强太多了&#xff0c;批处理只能在当前节点循环&#xff0c;做一些简单的循环任务还不错…

【日记】狗尾巴草与暗恋(1519 字)

写在前面 消极内容注意 正文 好想吃火龙果。 下周会变得异常艰难。因为事情已经垒到天上去了&#xff0c;还要来检查。 上午&#xff0c;同事送了一点水果&#xff0c;我从来没见过。问了一下别人&#xff0c;有的说是灯笼果&#xff0c;有的说是菇凉果、姑娘果。搜了一下&am…

深入理解Elasticsearch:让搜索性能飞起来!

Elasticsearch 概述 Elasticsearch是一个基于lucene、分布式、通过Restful方式进行交互的近实时搜索平台框架。 ELK 技术栈是Elasticsearch、Logstash、Kibana三大开元框架首字母大写简称。 而Elasticsearch 是一个开源的高扩展的分布式全文搜索引擎&#xff0c; 是整个 ELK技术…

polarctf靶场[WEB]Don‘t touch me、机器人、uploader、扫扫看

目录 [web]Dont touch me 考点&#xff1a;查看源代码、前端 [web]机器人 考点&#xff1a;robot协议 工具&#xff1a;御剑&#xff0c;kali dirsearch [web]覆盖 考点&#xff1a;parse_str覆盖 [web]扫扫看 考点&#xff1a;目录扫描 工具&#xff1a;御剑、kali d…

【冒泡排序算法】输入n个数进行排序

要求&#xff1a;输入n个数进行排序 实现&#xff1a;使用冒泡排序算法&#xff0c;使用C语言实现 冒泡排序的基本原理&#xff1a; 比较相邻元素&#xff1a;从数组的开始位置&#xff0c;比较每对相邻的元素。如果前一个元素大于后一个元素&#xff0c;则交换它们。重复过…