当前位置: 首页 > news >正文

C++软件开发值得推荐的十大高效软件分析工具

目录

1、概述

2、高效软件工具介绍

2.1、窗口查看工具SPY++

2.2、Dependency Walker

2.3、剪切板查看工具Clipbrd

2.4、GDI对象查看工具GDIView

2.5、Process Explorer

2.6、Prcoess Monitor

2.7、API Monitor

2.8、调试器Windbg 

2.9、反汇编工具IDA 

2.10、抓包工具Wireshark

3、总结


C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125529931C/C++基础入门与实战进阶(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_11931267.htmlVC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/124272585Windows C++ 软件开发从入门到精通(专栏文章,持续更新中...)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       作为C++软件开发人员,有没有思考过这些问题:如何提升日常工作中的开发效率?如何才能快速地分析并解决开发调试过程中遇到的各类问题?有哪些值得推荐的高效软件工具可以使用?作为从业多年的C++开发老兵,根据多年来的开发经历及取得的实战经验,今天给大家推荐十大高效C++软件分析工具。我们需要熟练使用这些工具,借助这些工具,可以高效快速地分析和排查软件开发调试过程中遇到的各种问题,从而有效地提升软件开发和维护的效率。

1、概述

       本文将以Windows系统中C++开发的应用软件为主线,对本文主体内容进行展开。运行在Windows系统中的应用软件主要是用C++、C#等语言开发的,其中的大部分都是用C++实现的。比如大家平时常用的Google Chrome浏览器、腾讯会议、PC版微信和QQ、企业微信、阿里钉钉、字节飞书、华为WeLink、百度网盘客户端、有道云笔记、PC版QQ音乐、PC版腾讯视频、酷狗音乐等软件都是用C++开发实现的。

       在这些C++软件开发和维护的过程中,会用到一些高效的软件分析工具去辅助分析和排查软件运行中遇到的各式各样的问题,今天就把我在开发调试过程中用的一些列工具分享给大家。我日常使用的分析工具有SPY++、Dependency Walker、剪切板查看工具Clipbrd、 GDI对象查看工具GDIView、Process Explorer、Process Monitor、API Monitor、调试分析工具Windbg、交互式反汇编工具IDA、抓包工具Wireshark等。本文将结合具体的案例及使用场景,对这些工具一一进行详细的介绍。

       通过公司内部培训交流以及网上技术沟通得知,很多C++软件开发人员都没有用过GDIView、Process Explorer、Process Monitor、API Monitor、Windbg、IDA等高效分析工具,甚至都没听说过,他们分析排查问题的方式还停留在用IDE调试和查看打印日志的老方法上,效率相对较低,所以很有必要给大家普及一下这些高效的分析工具,大家都值得拥有!希望大家在今后的开发工作中能将这些工具用起来,去有效地提升软件开发调试的效率。

有人可能会问,你怎么了解到这么多工具的?其实这些技能都是通过项目实践不断积累得来的,有的是大家都用的,有的是同事或朋友推荐的,有的是网上搜索问题时别人建议的。我已经熟练掌握这些工具的使用,已经将这些工具全面地应用到商业项目的问题分析中,解决了开发调试中遇到的多个问题,极大地提升了分析问题和解决问题的效率。

2、高效软件工具介绍

2.1、窗口查看工具SPY++

       SPY++是微软IDE软件Visual Studio自带的一个小工具(spyxx.exe),该工具可以查看当前系统中打开的所有窗口的信息(包含显示和掩藏的窗口),在做UI界面编程分析窗口问题时该工具比较有用。

       SPY++的主界面如下所示:

使用该工具,我们可以来查看目标窗口的位置、大小、窗口样式、父窗口等信息,如下所示:

       对于可见的窗口,可以直接将探测按钮拖动到目标窗口上:

直接查看目标窗口的信息。

       对于掩藏的、不可见的窗口,也可以直接在SPY++主窗口中的窗口列表中以窗口标题、类名、窗口句柄等关键字去搜索目标窗口,搜索到后查看窗口属性即可。

       在模仿其他软件实现一些特效窗口时,通过这个工具查看特效窗口的一些属性,然后去参考相关属性的设置。我们也可以将SPY++列表中所有的窗口(当前系统中创建的所有窗口)信息保存到文件中,操作入口如下所示:

这在分析窗口异常崩溃的问题会很有用。

2.2、Dependency Walker

        Depenency Walker是微软提供的一个库依赖查看工具(depends.exe),该工具可以查看二进制文件exe和dll动态库的导出接口信息,也可以查看二进制文件的库依赖关系。这个工具虽然很小,却很实用,是分析软件因为库依赖问题导致的启动报错的最直接工具。该工具是早期Visual Studio自带的工具,现在的Visual Studio不再打包该工具了,可以到Depenency Walker官网上去下载。

       Dependency Walker的主界面如下所示:

2.2.1、排查启动报找不到dll库的问题

       一个exe程序的启动过程大概是这样的:

用户启动exe程序时,系统会分配对应的进程空间,首先去读取exe文件中的PE头信息,读出exe主程序依赖的所有dll库信息,然后系统将这些依赖的dll库加载到当前进程空间中(加载到进程空间的dll库包括exe开发者开发的dll库,也包括依赖的一些操作系统的dll库),待依赖的库完成加载之后,再去加载exe文件,然后进入exe文件中的main函数,这样exe程序就启动起来了。

如果加载依赖库时找不到依赖库文件,或者找到的依赖库的版本不对,会直接弹窗报错,提示程序启动失败。Depenency Walker工具正是用于排查这类问题的,比如程序启动时缺少库报错、在某个dll库中找不到某个接口报错等。

       以以前遇到的一个问题为例,程序启动时报如下的错误:

提示找不到MSVCP100D.dll运行时库(D对应debdebug版本的运行时库),程序是release版本的,怎么会依赖debug版本的运行时库呢?估计是底层依赖的dll库(底层的库包括底层的业务库、网络库、协议库、组件库、音视频编解码库等)发布的有问题,错误地把debug版本的库发布到我们release版本的exe产品流中了。

       于是用Dependency Walker打开exe程序,查看其依赖的库,看看哪个库依赖了的debug版本的MSVCP100D.dll,可以查到:

是截图中的dll库依赖了debug版本的MSVCP100D.dll,找到该问题库的维护组,让他们重新发布release版本的库即可。

2.2.2、排查动态启动的dll库启动失败的问题

       有的库可能是主程序动态启动的,如果这些动态启动的库因为其依赖的库有问题导致库动态加载失败,是不会弹出上面那种明确的提示框的。比如a.dll库是动态启动的,如果该库启动失败,会导致与之相关业务无法进行,此时可以先使用Process Explorer查看主程序的库加载情况(Process Explorer工具下面也会介绍,该工具会将目标进程加载的所有的dll库显示出来),确定a.dll有没有启动起来:

注意打开Process Explorer后,要点击上方工具栏中的View DLLs图标按钮才能查看目标进程加载的dll列表,然后在该列表中查看目标库有没有启动起来。

       假设a.dll没有启动起来,有可能其依赖的库找不到,也可能该库中调用的接口在其依赖的库中找不到。我们再用Dependency Walker直接打开a.dll查看其库依赖的情况即可找到原因。如果库有问题,在其前面会显示红色或黄色警告图标:

黄色图标表示系统中找不到该库,红色图标表示某接口在某个库中找不到。

       这里需要注意一下,Dependency Walker打开目标文件后,默认会展开目标文件依赖的所有的库,其中包括很多Windows系统库,我们要通过经验加以甄别,将Windows系统库都折叠起来跳过去(要熟悉一些常见的Windows系统库,比如ntdll.dll、user32.dll、kernel32.dll等。),一般问题都出在我们应用程序的业务库中的。

       此外,还有一些api-ms开头的库,在Dependency Walker中显示黄色图标,一般是没问题的。这些api-ms开头的库,一般是应用程序开发者需要打包到产品的安装包中的,这些库在安装时会自动释放到程序的安装路径中的,以腾讯会议的安装目录为例可以看到这些库:

        最后有一点需要说明一下,Dependency Walker在win10系统中打开文件时特别慢,有可能是Dependency Walker版本比较老(好几年前出的版本),对win10系统的兼容性不好导致的,打开文件时可能要等上好几分钟才能打开。在这种时候,需要耐心等待一会。

       关于使用Dependency Walker排查项目问题实例,可以参见我之前写的文章:
使用Dependency Walker和dumpbin工具定位C++软件启动时找不到接口的报错问题icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125665650

2.3、剪切板查看工具Clipbrd

       该工具主要用来查看剪切板中包含了哪些剪切板格式的数据,在处理数据的复制与粘贴时很有用!在XP系统中,该工具是系统自带的,但自win7系统开始就不再带该工具了,需要的话可以到XP系统中拷贝出来,也可以到网上去下载。

有人可能会说,这都什么年代了,谁还用XP系统啊!确实,现在确实很难找到还使用XP系统的电脑了。不过我们在2009年刚毕业那些年,一直用的还是XP系统。然后出现了Win7系统,并逐步普及,到最近几年已经完全普及了Win10系统,新版本的Win11都出来了。几年前,微软甚至还说Win10将是Windows系统的终极版本,结果微软还是食言了,近年又搞出了Win11。

       我几年前参与了一款IM即时通讯软件的开发,要实现聊天窗口中聊天内容的复制和粘贴功能,要支持多种剪切板的格式,要支持与其他常用IM软件比如QQ、PC版微信、企业微信等间的复制粘贴互通,即在IM软件的聊天框中对图片与文字的混合内容进行复制,然后将内容粘贴到QQ等的聊天输入框中,QQ的输入框中可以正常显示;从QQ中复制图片和文字的混合内容,也要能够粘贴到我们的IM软件中并正确显示出来。

        那如何知道QQ等软件都支持哪些剪切板格式呢?使用Clipbrd就可以看到。具体的做法是,我们先在QQ的聊天框中复制图片和文字的混合内容,然后打开Clipbrd剪切板查看工具,在Clipbrd的菜单栏中点击查看,在弹出的菜单中就可以看到QQ在复制图片和文字的混合内容时都生成了哪些剪切板格式的数据,如下图所示:

从图片中可以看出,QQ生成了多种剪切板格式的数据,其中QQ_Unicode_RichEdit_Format格式是QQ专有的剪切板数据格式, HTML Format格式则是通用的格式,是很多IM软件和邮箱都支持HTML Format格式。

       系统支持的预定义剪切板格式有CF_TEXT(文字)、CF_UNICODETEXT(Unicode文字)、CF_BITMAP(位图图片)和CF_HDROP(可拖拽数据)等,这些基本格式可以直接使用。对于QQ_Unicode_RichEdit_Format、HTML Format等这些用户自定义格式,则需要使用API函数RegisterClipboardFormat向系统注册才能获得对应CF值,这样自定义的剪切板格式是以“QQ_Unicode_RichEdit_Format”、“HTML Format”字符串作为标识的。

       如果我们要知道某种自定义剪切板格式对应的数据内容与格式,可以编写类似如下的测试代码,去获取指定剪切板格式的数据内容:

HANDLE hClip = NULL;
char *pBuf = NULL;
WCHAR* pwchBuf = NULL;
char* pTemp = NULL;// 1、通过名称去注册剪切板格式
m_dwClipFormatQQ = ::RegisterClipboardFormat( _T("QQ_Unicode_RichEdit_Format") ); 
// 2、打开剪切板
BOOL bRet = ::OpenClipboard( NULL );
if ( !bRet )
{return;
}// 3、获取指定剪切板格式的数据句柄
hClip = GetClipboardData( m_dwClipFormatQQ );
if ( NULL == hClip )
{CloseClipboard();return;
}// 4、调用GlobalLock函数获取数据buffer地址
pBuf = (char*)GlobalLock( hClip );
if ( NULL == pBuf )
{GlobalUnlock( hClip );CloseClipboard();return; 
}// QQ_Unicode_RichEdit_Format格式的数据(字符串),是以utf-8编码的,所以先将
// utf-8编码的字符串转成Unicode编码的
int nNum = MultiByteToWideChar( CP_UTF8, 0, pBuf, -1, NULL, 0 );
pwchBuf = new WCHAR[nNum];
MultiByteToWideChar( CP_UTF8, 0, pBuf, -1, pwchBuf, nNum );// 将转码后的字符串显示到UI界面上
CString strContent;
CopyUtf8ToCStringT( strContent, pBuf );
m_editContent.SetWindowText( strContent );
GlobalUnlock( hClip );

        可以将指定格式的剪切板数据读出来,看看里面的数据格式是什么样子的。比如获取到的QQ_Unicode_RichEdit_Format剪切板格式的数据内容如下:

<QQRichEditFormat><Info version="1001"></Info><EditElement type="1" filepath="C:\Users\Administrator\AppData\Roaming\Tencent\Users\7100****\QQ\WinTemp\RichOle\MJR{P}JK{HS{077`IF_@$Y3.png" shortcut=""></EditElement><EditElement type="0"><![CDATA[123]]></EditElement><EditElement type="1" filepath="C:\Users\Administrator\AppData\Roaming\Tencent\Users\7100****\QQ\WinTemp\RichOle\L2_QM_EY}G3)R`76P9HYLPJ.png" shortcut=""></EditElement>
</QQRichEditFormat>

         获取到的HTML Format剪切板格式数据内容如下:

Version:0.9
StartHTML:00000112
EndHTML:00000461
StartFragment:00000126
EndFragment:00000425
<!doctype html><html><body>
<!--StartFragment --><DIV>
<IMG src="file:///C:\Users\Administrator\AppData\Roaming\Tencent\Users\710027094\QQ\WinTemp\RichOle\LVF%BQDXAUX@0MP2{(%$LLK.png" >123<IMG src="file:///C:\Users\Administrator\AppData\Roaming\Tencent\Users\710027094\QQ\WinTemp\RichOle\V8E90K]C]N%1G]8_Q(B48}8.png" >
</DIV><!--EndFragment-->
</body>
</html>

       我们可以参考这些剪切板格式的数据样式,在我们的软件中复制数据时构造这些格式的剪切板数据设置到剪切板中,然后就能和其他IM软件互通了。经实践,对于文字与图片的混合内容或者多张图片一起的复制和粘贴,我们得出了如下的结论:

1)要支持从其他软件中复制内容粘贴到我们的软件中,我们只需要解析通用的HTML Format剪切板格式数据就可以了;
2)要支持从我们软件复制粘贴到其他软件中,我们需要构建通用的HTML Format剪切板格式数据,还要构建粘贴到目标软件时目标软件支持的格式(剪切板中支持同时设置不同剪切板数据类型的数据),比如要将复制的内容粘贴到QQ中生效,则在复制内容时要构造QQ专用的QQ_Unicode_RichEdit_Format剪切板格式,只构造HTML Format剪切板格式,是没法粘贴到QQ中的(粘贴进去没法正常显示的)。飞秋、邮箱等软件都是支持通用的HTML Format剪切板格式的。

而对于纯文字的内容复制,我们只需要设置基础类型CF_TEXT和CF_UNICODETEXT就可以了;对于单张图片,我们设置基础的CF_BITMAP即可;对于多张图片,则要设置HTML Format和QQ_Unicode_RichEdit_Format格式,构造对应格式的数据了。

      关于剪切板编程和IM软件剪切板对通的更多细节,可以参见我之前写的文章:

IM即时通讯软件中的剪切板数据对通的实现细节icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/123621993

2.4、GDI对象查看工具GDIView

       GDIView是nirsoft公司开发的一个用来显示每个进程使用的GDI对象句柄数的工具,它显示了每种GDI对象的数量以及整个进程占用的GDI对象总数,主要用来帮助开发人员追踪软件中的GDI句柄资源泄漏问题可以自行到GDIView的官网上下载该工具。

       GDIView工具的主界面如下所示:

GDI对象是什么:

GDI是Graphics Device Interface(图形设备接口)的缩写,UI界面应用程序在绘制图片、绘制直线等图形、输出文字时都会用到GDI对象。常见的GDI对象有Pen(笔)、Font(字体)、Bitmap(位图)、Brush(画刷)、Region(区域)、DC(设备上下文)等。

GDIView工具在排查GDI对象泄露问题时,非常好用。

2.4.1、GDI对象泄漏

       所谓GDI对象泄露是指,调用系统API函数创建(Create)了GDI对象,在使用完成后,没有去删除(Delete)GDI对象。比如某段执行UI绘制代码有GDI对象泄露的问题,并且这段有问题的代码会被频繁地执行,随着软件的长时间运行,占用的GDI对象可能越来越多(泄露的GDI对象一直没释放,越积越多),当进程的GDI对象总数接近或到达10000个,绘图会出现异常,紧接着程序就会出现卡死或崩溃。这个GDI对象泄漏可以通过自动化工具拷机测试复现出来(比如使用按键精灵录制操作去自动执行拷机测试)。

在Windows系统中,一个进程占用的GDI绘图对象不允许超过10000个,当接近或超过10000时程序绘图就会出现异常,甚至出现崩溃闪退的问题。

       当程序绘图出现异常时,可以先在Windows系统自带的任务管理器中查看目标进程的GDI对象总个数:

如果GDI对象数接近或者达到10000个,则说明程序中肯定有GDI对象泄露了。然后再使用GDIView工具去查看哪些GDI对象在持续增长,没有释放,这样在排查代码时就比较有针对性了,就能很快定位问题了。

2.4.2、GDI对象泄漏示例

       举一个简单的内存泄露的例子,如下所示:

HPEN hPen2 = ::CreatePen( PS_SOLID, 5, RGB(255,0,0));
HBRUSH hBr = ::CreateSolidBrush( RGB(0, 255, 0) );
::SelectObject( hMemDC, hBr );
HPEN hOldPen = (HPEN)::SelectObject( hMemDC, hPen2 );
::Rectangle( hMemDC, 0, 0, 20, 20 );
::SelectObject(hMemDC, hOldPen);

代码中创建了一个pen对象和一个brush对象,结果在这两个对象使用完毕后没有将这两对象给delete掉,这样就导致了GDI对象的泄露。如果上述代码在程序运行的过程中被频繁的执行,则pen对象和brush对象会持续的增长,使用GDIView工具就能看到这两个GDI对象数在持续的增长。

2.4.3、GDI对象泄漏项目实例

       以前帮公司webrtc开发维护小组排查过一个DC对象内存泄露的例子,在他们的代码中调用GetDC去获取窗口DC对象,结果在使用完成后没有调用ReleaseDC将DC对象释放掉,问题代码如下:

#if defined (WEBRTC_WIN)//修正程序开启DWM导致的鼠标位置问题int desktop_horzers = GetDeviceCaps( GetDC(nullptr) DESKTOPHORZRES);int horzers = GetDeviceCaps(GetDC(nullptr),HORZRES);float scale_rate=(float)desktop_horzers/(float)horzers;relative_position.set( relative_ position.x()*scale_rate, relative_ position.y()*scale_rate );
#endif

就导致了DC对象的泄露,导致他们的程序在运行一段时候后程序的窗口显示异常(窗口绘制异常),紧接着程序就发生了崩溃。修改后的代码如下:

#if defined (WEBRTC_WIN)//修正程序开启DWM导致的鼠标位置问题HDC hDC = ::GetDC(nullptr);int desktop_horzers = GetDeviceCaps( hDC, DESKTOPHORZRES);int horzers = GetDeviceCaps(hDC,HORZRES);float scale_rate=(float)desktop_horzers/(float)horzers;relative_position.set( relative_ position.x()*scale_rate, relative_ position.y()*scale_rate );::ReleaseDC(nullptr, hDC); // 增加了这一句,解决GDI对象泄漏问题
#endif

       我们查到有GDI对象泄漏问题,因为之前的版本是没有GDI泄漏的,并且查看svn代码提交记录确定上层最近没修改过与GDI有关的代码,而底层的webrtc库最近修改过几个问题,所以怀疑是webrtc库修改的代码导致的。但维护webrtc的同事说他们新增的代码并没有操作GDI对象去绘图,应该不是他们的问题。后来不得已去他们那边查看webrtc开源库的修改记录,看到了上述有问题的代码,然后他们才承认是他们新增的代码引起的。这可能也是和他们很少搞UI编程有关系吧,对GDI对象泄漏问题不太敏感。

这是大家的思维定势,软件出问题了,最开始总是说这肯定不是我们模块的问题,应该是其他组维护的模块引起的。

       关于使用GDIView排查项目中遇到的问题实例,可以参见我之前写的文章:

使用GDIView工具排查GDI对象泄漏问题icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125399896

2.5、Process Explorer

       Process Explorer是Winternals公司(该公司已经被微软收购)开发的增强版任务管理器软件工具(procexp.exe),功能要比Windows系统自带的任务管理器的功能多很多。使用该工具可以查看服务、进程、线程、模块、句柄、磁盘使用状态、网络使用状态等多类信息。Process Explorer和下面要讲到的Process Monitor都是Winternals公司开发的免费工具,被放置在Sysinternals Suite工具包中。

Sysinternals Suite包含了一系列免费的系统工具,其中有大名鼎鼎的Process Explorer、Process Monitor、FileMon、RegMon等,如果把系统管理员比喻成战士的话,那么Sysinternals Suite就是战士手中的良兵利器。熟悉和掌握这些工具,并且对Windows的体系有一定的了解,将大幅度的提高日常的诊断和排错能力。

       Process Explorer的主界面如下所示:

微软在2006年7月收购了Winternals公司,更重要的是,微软通过此并购网罗了该公司的两位重量级创始人Mark Russinovich及Bryce Cogswell。其中,Mark Russinovich目前担任微软Azure云计算CTO首席技术官。Mark Russinovich 在微软开发了非常多的系统工具,比如 winobj、sysmon、diskmon 和进程监视器,同时他还著有著名Windows内核书籍《Windows Internals》(中文名为:深入解析Windows操作系统),慢慢地Mark Russinovich已经成为微软的象征。此外,Mark Russinovich 还精通逆向工程,震惊世界的索尼BMG光盘复制保护丑闻就是他发现的。

       对于Sysinternals Suite工具包的获取,可以到微软的https://live.sysinternals.com/ 页面去下载,需要哪个工具就下载哪个工具:

注意,在Sysinternals Suite工具包中,Process Explorer缩写成procexp.exe,Process Monitor缩写为procmon.exe。

2.5.1、使用Process Explorer查看进程的详细信息

       在日常工作中,我们主要用该工具来查看进程的相关信息,以排查程序运行过程中出现的问题。平时用到的主要功能有:

1)查看进程启动时传入的命令行启动参数;
2)查看进程加载了哪些dll库(通过该功能确定目标dll有没有启动起来),以及这些库的详细信息;
3)查看进程的磁盘和网络使用统计信息;
4)查看进程的各个线程的信息,可以看到各线程的CPU占用比例和线程的函数调用堆栈(在排查进程CPU占用高时会用到,找到占用CPU高的那个线程);
5)查看进程的GPU占用情况(判断程序是否使用GPU硬件编解码);
6)查看进程的虚拟内存的占用情况。
7)查看进程占用的句柄信息,比如文件句柄、线程句柄、注册表句柄等。

它是我们在日常工作中使用很频繁的一个工具!下面紧接着讲几个使用Process Explorer的常用场景,这些场景在我们的项目都有频繁的使用。

2.5.2、查看目标进程的dll库加载情况

       如果要查看进程的库占用情况,需要在第一次启动该工具时点击工具栏中的“View DLLs”图标按钮,才会显示目标进程加载的库列表。默认情况下显示的是句柄占用信息。

       在进程列表中,点击选择目标进程,下方就会显示加载了哪些库,然后取查看这些库的信息,比如占用库的路径,占用库的版本。通过库的路径或版本,确定是否加载了正确版本的库。

       此外,代码中有些库可能是动态加载的,可以在库列表中看目标dll库有没有启动起来(加载到进程空间中),如果没启动成功,一般是库依赖的库有问题,就需要使用Dependency Walker去打开启动失败的库,查看该目标库依赖的库是否有问题。

2.5.3、查看目标进程中各线程的CPU占用情况,排查CPU占用高的问题

        除了查看依赖的dll库信息,还可以查看目标进程中的所有线程信息。双击进程列表中的目标进程,在弹出的窗口中点击Threads标签页,就能看到进程中的所有线程的信息。比如我们在排查目标进程的高CPU占用问题时,按照上述操作去查看进程中的线程列表,列表中看到一个线程占用了很高的CPU,如下所示:

应该就是这个线程导致进程的高CPU占用了。于是双击该线程,就看到线程当前的函数调用堆栈了,如下:

根据线程的函数调用堆栈中调用的函数,对照着C++源码,就能确定当前线程是哪个业务线程了。这个地方需要注意一下,要看线程函数调用堆栈中详细的函数信息,需要将相关模块的pdb符号库文件提前放到模块的同级目录中。

2.5.4、查看目标进程的GPU占用情况

       双击进程列表中的目标进程,在弹出的窗口中,点击GPU Graph标签页,就看可以看到目标进程对GPU占用的情况:

主要用于判断目标进程是否使用了CPU的GPU硬件单元。在很多视频会议、视频监控的软件中,可能会使用CPU上的GPU单元,进行视频的硬编硬解,从而节省对CPU的消耗。直接使用CPU进行视频的编解码操作,我们称之为软编软解,会消耗大量的CPU资源。如果能使用GPU进行硬编硬解,则能有效地较少对CPU的占用。

2.5.5、推荐一款与Process Explorer类似的工具Process Hacker

       Process Hacker是一款类似于Process Explorer功能丰富的进程查看管理工具(ProcessHacker.exe),可以查看服务、进程、线程、模块、句柄、磁盘使用状态、网络使用状态等。Process Hacker主界面如下:

       Process Hacker界面要更酷炫一些,功能上基本和Process Explorer差不多的。此外,Process Hacker是完全开源的,是一位华人软件开发者开发并开源的,可以到Process Hacker官网上下载开源代码。

Process Hacker功能很完备,可以到开源代码中查看诸多功能是如何实现的。

       关于使用Process Explorer排查项目中遇到的问题实例,可以参见我之前写的文章:
使用Process Explorer和Dependency Walker定位dll库动态启动失败的问题icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125216591


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

专栏1:(该精品技术专栏的订阅量已达到490多个,专栏中包含大量项目实战分析案例,有很强的实战参考价值,广受好评!专栏文章持续更新中,预计更新到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++软件辅助分析工具有PE工具、Dependency Walker、Process Explorer、Process Monitor、API Monitor、Clumsy、Windbg、IDA Pro等,本专栏详细介绍如何使用这些工具去巧妙地分析和解决日常工作中遇到的问题,很有实战参考价值!

专栏3: 

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

以多年的开发实战为基础,总结并讲解一些的C/C++基础与进阶内容,以图文并茂的方式对相关知识点进行详细地展开与阐述!专栏涉及了C/C++领域的多个方面的内容,同时给出C/C++及网络方面的常见笔试面试题,并详细讲述Visual Studio常用调试手段与技巧!

专栏4:   

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

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

专栏5: 

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

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


2.6、Prcoess Monitor

       Process Monitor一款系统进程监视工具(Procmon.exe),主要用来监测目标进程的注册表和文件操作活动。该工具也是微软Sysinternals Suite工具包中的一个工具,程序名缩写为procmon.exe,可以到微软的https://live.sysinternals.com/ 页面去下载(上面已经讲过)。

       该工具的具体使用方法是,先点击工具栏的漏斗按钮,添加要监测的目标进程

然后在工具栏将不需要监测的活动类型取消掉:(一般我们只监测文件活动和注册表活动)

2.6.1、监测注册表活动

       比如想知道目标进程在执行某个操作时将相关信息写到哪个注册表路径中,都写入了哪些内容。可以使用该工具对注册表活动进行监测。目标进程会调用系统库,系统库会频繁操作注册表,所以监测出来的注册表读写记录会比较多,需要使用关键字对监测到的结果搜索。

2.6.2、监测文件活动

       比如测试同事在测试时发现软件在桌面或其他路径中生成了一些莫名的日志文件,他们需要定位到日志是哪个模块生成的,需要将生成日志文件的代码清理掉(在桌面上生成一些莫名的日志文件,很奇怪的!),此时可以使用该工具对文件活动进行监测。

       同样,目标进程对文件的操作很频繁,会监测到大量的记录,可以在监测列表中以文件名进行搜索,然后找到生成目标文件的操作。找到生成目标文件的记录,双击打开该记录,就会弹出与该操作相关的函数调用堆栈上下文

通过堆栈中函数调用的上下文,就可以看出日志文件是哪个模块、哪个函数生成的,这样就可以到函数中修改代码,将生成日志的操作关闭掉。

       关于使用Prcoess Monitor排查项目中遇到的问题实例,可以参见我之前写的文章:

使用Process Monitor工具监测进程对注册表和文件的操作icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125436195

2.7、API Monitor

        API Monitor是rohitab出品的一个用来探测进程对API函数调用的工具,使用该工具可以窥探软件在实现一些功能时都调用了哪些Windows系统API函数,通过这些探测出来的API函数去估计出目标软件某些功能的实现方法。不仅可以探测出调用了哪些API函数,还能探测出调用API函数时都传递了什么样的参数,然后可以参照这些API函数及参数去实现类似的功能或者去尝试解决在开发软件过程中遇到的一些问题。

       API Monitor工具的主界面如下所示:

2.7.1、API Monitor帮我们解决问题的实例

       该工具非常的有用,帮我们解决了项目中的多个问题。比如在处理我们软件setup安装包的管理员权限问题、64位系统中创建桌面快捷方式时的图标问题,都是通过该工具对某主流软件的安装包的监测,找到了解决问题的办法。

       再比如在实现文件传输的打开文件所在文件夹功能时,使用了该工具对某主流软件和迅雷进行监测,找到了解决问题的办法,甚至还发现了迅雷的一个掩藏很深的bug。

       还有一个实例,我们软件在打开chm文件时遇到了一些问题,使用该工具监测了Beyond compare文件内容比较软件,该软件有打开.chm帮助文档的操作,获得了Beyond compare软件在调用对应的API函数时传递的参数。参照这个参数,解决了我们软件中的问题。

       此外,该工具除了可以监测对系统API的调用,还可以监测对第三方库的导出函数的调用。

2.7.2、API Monitor的具体使用方法

       该工具的具体使用方法以监控某安装包程序为例,先将目标监控程序启动起来,在左侧的函数列表中搜索要监控的API,比如ShellExecute和CreateProcess,将搜索到目标函数都勾选上:

然后在左下侧的进程列表中,选择要监控的进程,点击右键菜单中的“Start Monitoring”即可开启监控。然后让目标监控程序继续跑下去,这样就能监控到目标API函数的调用情况了:

       关于使用API Monitor排查项目中遇到的问题实例,可以参见我之前写的文章:

使用API Monitor监测到目标程序对系统API函数的调用icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125362394

2.8、调试器Windbg 

       Windbg是微软出品的Windows平台下强大的用户态和内核态调试工具,与微软的IDE工具Visual Studio相比,它是一个轻量级的调试工具。所谓轻量级指的是安装快速轻便,但其调试功能,却比Visual Studio更为强大。

       Windbg的主界面如下所示:

2.8.1、使用Windbg分析C++软件异常

       Windbg是分析与排查C++软件异常的利器,在排查软件异常与崩溃时非常有用,是我们日常工作中用的最多的工具之一!

       通过在公司内部及网上调研发现,很多C++程序员普遍在软件调试与异常分析方面比较欠缺,所以很多人这方面的技能都有待加强。他们分析软件异常问题还停留在很原始的状态,要么通过IDE调试,要么通过分析日志去分析。对于很难复现的问题,则很难去用IDE调试排查,而使用日志去排查效率非常低,很难定位问题。而使用Windbg调试器去分析,可以极大地提升排查问题的效率,有些比较典型的异常崩溃,分分钟就能定位出原因,当然这其中可能需要一些经验。

2.8.2、IDE看不到有效的函数调用堆栈,Windbg动态调试却可以看到

       在排查软件异常时,一般是通过发生异常时的函数调用堆栈去分析的,但有时即使能用IDE调试源码复现问题,但却看不到有效的函数调用堆栈,也没法做进一步分析。这类场景我们遇到过很多次了。比如一个最典型的场景,当程序中发生线程栈溢出时,Visual Studio会直接退出调试状态,这样也就无法看到异常发生的函数调用堆栈了。再比如,我们在调试状态发生崩溃,但切换到函数调用堆栈页面,却看不到有效的函数调用堆栈。遇到这些问题时,可以尝试使用Windbg启动目标程序调试运行,问题复现后可能就能看到完整的函数调用堆栈了,问题可能很快就能迎刃而解了。

       以上个星期帮新人搭建项目的Debug运行调试环境时遇到的问题为例,环境搭建好后启动Debug调试,结果刚启动程序就发生了崩溃,弹出如下的提示框:

Visual Studio中断下来,将提示窗口关闭,切换到call stack函数调用堆栈窗口中查看函数调用堆栈:


但看不到完整的函数调用堆栈。这个崩溃是必现的,既然Visual Studio看不到有效信息,于是想到使用Windbg启动Debug版本exe程序。

       因为是exe启动时的崩溃,所以Windbg一启动exe就产生崩溃,Widnbg感知到了异常并中断下来,输入kn命令查看函数调用堆栈,看到了如下的详细函数调用堆栈:

这个函数调用堆栈时有效的,通过堆栈得知崩溃发生在initglobe函数中,并且看到了代码的行号,于是去查看C++源码最终找到出了问题。

       在这个问题中,IDE开发工具Visual Studio在崩溃时看不到有效的函数调用堆栈,但使用Windbg动态调试目标程序复现崩溃时是可以看到的。

2.8.3、Windbg静态分析dump文件与Windbg动态调试

       使用Windbg分析软件异常有两种方式,一种是静态分析dump文件,一种是使用Windbg动态调试目标程序(可以直接使用Windbg启动目标程序,也可以将Windbg附加到已经运行的目标进程上)。

       对于静态分析dump文件的方式,首先需要在软件发生异常时软件自己自动捕获到,并自动生成dump文件。一般我们需要在软件中嵌入异常捕获模块,可以使用Google开源的CrashRpt库(该开源库是有缺陷的,没法做到对所有模块的异常捕获,可以使用微软的detours开源代码中的技术进行改进),在软件发生异常时异常捕获模块感知到,自动生成包含异常上下文的dump文件。这样我们在事后将dump文件取过来分析就可以了。我们在项目上基本使用这种方式去事后分析异常。

       但在实际场景下,有少数异常崩溃,异常捕获模块可能捕捉不到,或者感知到后,在生成dump文件时产生了二次崩溃,这样就没有dump文件可供分析了。遇到这类问题,则需要使用Windbg将程序启动起来或者将Windbg附加到已经启动的程序进程上,即将Windbg挂到目标进程上和目标进程一起跑,如果目标进程发生异常,Windbg会第一时间感知到并中断下来,这样就可以拿到函数调用堆栈进行分析了。

2.8.4、Windbg上手与汇编代码

       很多人可能觉得Windbg上手比较难,其实Windbg的入门并不难,只需要掌握常用的Windbg命令,了解函数调用的栈分布图,知晓函数调用的栈回溯原理,基本就能用起来了。但如果要深入分析,就需要有较深的软件开发经验和汇编语言基础了。但要熟练掌握软件异常排查的技能,还是需要不断实践,C++异常崩溃的原因是五花八门的,需要在排查问题中不断的积累、不断的总结!排查的问题越多,积累就越多,就越有心得!在问题中增长经验,在总结中升华技能!这是近几年来做这类工作内容的最大心得!

        搞C/C++开发,了解汇编语言,掌握一些基础的汇编知识,是很有必要的。这不仅有利于理解C/C++是如何运行的(有些问题需要从汇编代码的角度去看,从汇编代码的角度才能将问题看清楚),而且有利于从较深层次上分析一些复杂的软件异常。有时在分析一些异常崩溃时,需要查看C++源码对应的汇编代码才能最终搞清楚的。程序最终是崩溃在某套汇编指令上,汇编指令才能最本真、最直接地反映问题的所在。

       此外,有时我们为了提高代码的执行效率,会直接在C++代码中嵌入一段汇编代码(可能是嵌入一小段代码,也可能是整个函数都是汇编代码实现的)。之前我在协助音视频编解码组的同事排查异常崩溃时,看到了音视频编解码的部门源码,他们直接将一个频繁调用的函数直接用汇编代码去实现,以提升音视频编解码的执行效率。

有人可能会问,经过IDE编译出来的二进制文件中也都是汇编指令,你人为的添加一段汇编代码,都是汇编代码,为啥会有执行速度上的差别呢?因为源代码经过编译器的处理生成的汇编代码在实现上可能不是最优的,这要依赖编译器,而我们人为地添加汇编,可以直接控制汇编代码,保证汇编代码是最优的,不再依赖编译器。

        关于如何使用Windbg以及使用Windbg排查问题的实例,可以参看我的专栏,里面有多篇文章进行了详细的阐述:

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

2.9、反汇编工具IDA 

       IDA(The Interactive Disassembler)是比利时Hex-Rays公司开发的一款强大的交互式反汇编工具,可以直接打开exe或者dll等二进制文件,查看文件中的汇编代码。

       有时在分析一些C++软件异常崩溃时,需要查看C++源码对应的汇编代码才能搞清楚,我们一般使用IDA去查看目标模块的汇编代码。程序最终是崩溃在某套汇编指令上,汇编指令才能最本真最直接地反映问题的所在的。有时要搞清楚代码奔溃的本质,还是要看汇编代码的。

IDA是俄罗斯天才程序员Ilfak Guilfanov(伊尔法克·吉尔法诺夫)开发的,IDA由比利时Hex-Rays公司出品,Ilfak Guilfanov则是公司的CEO。

俄罗斯盛产天才程序员,Java程序员熟知的IDE工具IDEA(IntelliJ IDEA)就是3个俄罗斯天才程序员开发的,他们在捷克成立了伟大的JetBrains公司,该公司除了开发出IDEA,还研发出了Python开发环境PyCharm、Web前端开发环境WebStrom、Go语言开发环境GoLand、php语言开发环境PhpStorm等多个被业界广泛采用的重量级IDE开发工具。

被IT界广泛使用的Web及反向代理服Nginx,是俄罗斯人Igor Sysoev(伊戈尔·赛索耶夫)开发的。

在大数据领域广泛应用的高性能数据库ClickHouse,是俄罗斯的Yandex 公司开发并开源的,字节跳动公司推出的具有更高性能数据库ByteHouse就是在开源ClickHouse的基础上改进而来的。

俄罗斯除了盛产程序员,还擅长产出顶级的数学家和化学家,华为俄罗斯研究所就招募了不少俄罗斯数学家去做基础研究。

2.9.1、IDA程序图标的由来

       IDA的程序图标是世界首位计算机程序员,如下所示:

对,你没看错,她是世界上第一位程序员,女程序员,她叫阿达·洛芙莱斯(Ada Lovelace)。IDA软件用她的头像作为图标,目的是为了纪念这位伟大的女程序员。

Ada Lovelace设计了巴贝奇分析机上解伯努利方程的一个程序,并证明当时的19世纪计算机狂人巴贝奇的分析器可以用于许多问题的求解。她甚至还建立了循环和子程序的概念。由于她在程序设计上的开创性工作,Ada Lovelace被称为世界上第一位程序员。

2.9.2、使用IDA协助排查C++软件异常

       在我的日常工作中,IDA主要是来辅助Windbg去分析和排查软件异常问题的。分析问题时,我们用IDA打开二进制文件查看汇编代码,一般是对照着C++源码去阅读汇编代码上下文的。

       Windbg中也能查看到汇编代码的上下文,但Windbg中显示的汇编代码没有任何注释,很难将汇编代码和C++源代码对应起来的。一般撇开C++源代码直接去读汇编代码上下文是很难的,除非你有非常强大的汇编功底与反汇编能力。

       此外,在release下编译代码时,编译器会对代码进行大量的优化,所以有时汇编代码很难和C++源代码一一对应起来。而IDA在解析出二进制文件的汇编代码时,会添加很多注释,在二进制文件有pdb符号库的情况下,IDA会添加更多的注解(有pdb时,可以看到每个函数名称以及函数中的变量信息),所以使用IDA查看汇编代码上下文要方便多了,能很好地将汇编代码和C++源代码对应起来。

2.9.3、使用IDA查看二进制文件的汇编代码,排查第三方安全软件bug

       有次客户那边出现崩溃问题,正是公司的技术大牛直接使用IDA查看第三方安全软件的汇编代码定位出来的。我们的软件部署到某个客户的系统中,会出现频繁的崩溃。客户的安全等级比较高,系统中安装了多个第三方安全软件,这些安全软件一般为了实现对目标程度的监控,都会注入到系统的进程中进行实时监测,我们初步怀疑是安全软件注入引起的。但客户说系统中的其他软件运行都没问题,为啥就你们的软件有问题呢?

       如果怀疑是第三方安全有问题,必须拿出证据,否则就是你们的软件有问题。这个问题比较棘手,于是找来了公司的顶级大牛,他直接使用IDA去查看注入模块的汇编代码,最终找到了原因。

       第三方安全软件为了监控所有进程在网络上收发的数据,直接将系统协议栈的socket套接字函数给hook了,hook成安全软件模块的接口,其中有个用于UDP下接收数据的recvfrom API接口,该接口的函数声明如下:

其中第5个参数和第6个参数都是指针,微软的说明如下:

第五个参数:[out] from
An optional pointer to a buffer in a sockaddr structure that will hold the source address upon return.
第六个参数:[in, out, optional] fromlen
An optional pointer to the size, in bytes, of the buffer pointed to by the from parameter.

       这两个参数都是指针,都是可选参数,我们在某块代码不用这两个参数,于是都传入NULL,正是这两个NULL参数,导致了第三方安全软件的注入模块产生了崩溃。

       通过使用IDA查看第三方安全软件的注入模块中recvfrom函数的汇编代码,函数中没有对该函数的第5个指针参数和第6个指针参数做是否为空的判断(这点太不严谨太不专业了!!!),然后就直接给传进来的参数变量赋值了,这样就操作NULL内存地址,产生了内存访问违例,导致了崩溃。拿出证据后,让客户向第三方安全软件提供商反馈,他们也承认是他们软件有上述缺陷的,并进行了相应的修改。

       关于IDA反汇编工具的详细介绍,可以参见我之前写的文章:

IDA反汇编工具使用详解icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/120635120

2.10、抓包工具Wireshark

       Wireshark是The Wireshark Team团队开发的一款开源的网络抓包软件工具,可以直接抓取网卡上收发的网络数据包,是分析网络问题的必备神器,也是我们日常开发工作中用的最多的工具之一!作为IT从业人员,使用Wireshark抓包进行网络数据分析,是一个基本的要求。

       现在的软件系统大多数都是基于网络的,不同形态的客户端软件(客户端软件包括PC端、安卓端、iOS端、嵌入式终端、web端等)需要通过网络与远端的服务器进行通信。网络中使用了大量的网络设备实现互联,网络设备上可能配置了大量的安全规则,基于网络的数据通信会遇到各式各样的网络及数据通信问题。

       Wireshark是排查网络问题的利器,用它可以抓取主机网卡上发出和接收的网络数据包,常用来分析各种网络异常问题,比如网络能否正常连通、是否有严重的抖动与丢包问题、接收到的和发送出去的网络数据是否有异常、网络通信的双方有没有正常完成相关协议流程的交互等。在分析时,可以在Wireshark中设置多种过滤条件,比如以IP和端口号过滤,使用ftp、http、websocket、xmpp等协议过滤,使用包含内容中的字符串过滤等。

       在排查网络问题时,需要了解基础的TCPIP网络知识,可以参看我之前写的这篇文章:
详解常用的基础网络知识(面试笔试常考内容)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/124433936文章中的基础网络知识,不仅日常工作中会用到,找工作时的笔试面试也常会涉及到。

       关于网络问题排查的项目实例,可以参看我的另一篇文章(姊妹篇):

网络问题排查实例集锦(实战经验分享)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/124643918

3、总结

       作为C++软件开发人员,是很有必要了解并熟练使用上述这些高效的工具的。其实,不仅仅是开发人员,这些工具对测试人员也有很大的价值。

       本文结合实际应用场景,对这些工具作了详细的介绍,希望能给相关开发人员及测试人员提供一些借鉴或参考。希望大家在今后的开发工作中能将这些工具用起来,去有效地提升软件开发、调试和测试的效率。

相关文章:

C++软件开发值得推荐的十大高效软件分析工具

目录 1、概述 2、高效软件工具介绍 2.1、窗口查看工具SPY 2.2、Dependency Walker 2.3、剪切板查看工具Clipbrd 2.4、GDI对象查看工具GDIView 2.5、Process Explorer 2.6、Prcoess Monitor 2.7、API Monitor 2.8、调试器Windbg 2.9、反汇编工具IDA 2.10、抓包工具…...

vue2老项目中node-sass更换dart-sass

更换原因&#xff1a;node-sass经常会出现node版本问题&#xff0c;就很麻烦 卸载项目中的node-sass sass-loader npm uninstall sass-loader sass 安装dart-sas sass-loader 推荐安装sass1.26.2 sass-loader7.3.1 npm install sass-loader7.3.1 sass1.26.2 从新配置vue.…...

源/目的检查开启导致虚拟IP背后的LVS无法正常访问

情况描述 近期发现48网段主机无法访问8.83这个VIP&#xff08;虚拟IP&#xff09;&#xff0c;环境是 8.83 绑定了两个LVS实例&#xff0c;然后LVS实例转发到后端的nginx 静态资源&#xff1b;整个流程是&#xff0c;客户端发起对VIP的请求&#xff0c;LVS将请求转发到后端实例…...

类和对象(四)

构造函数中的初始化列表 之前在实现构造函数时&#xff0c;主要是在函数体内进行赋值&#xff0c;而构造函数还有另一种初始化方式&#xff0c;通过初始化列表进行初始化。 初始化列表的使⽤⽅式是以⼀个冒号开始&#xff0c;接着是⼀个以逗号分隔的数据成员列表&#xff0c;…...

<PLC><HMI><汇川>在汇川HMI画面中,如何为UI设置全局样式?

前言 汇川的HMI软件是使用了Qt来编写的,因此在汇川的HMI程序编写过程,是支持使用qt的样式来自定义部件样式的,即qss格式。 概述 汇川的软件本身提供三个系统的style样式,我们可以直接使用,但是,如果系统提供的样式不符合你的需求,那么你可以对其进行修改,或者自己新建…...

在Git项目中添加并应用“.gitignore”文件

在Git项目中添加并应用.gitignore文件 创建或修改.gitignore文件&#xff1a; 在项目的根目录下创建一个名为.gitignore的文件。如果已经有此文件&#xff0c;可以直接修改。 在文件中添加您希望Git忽略的文件和目录。例如&#xff1a; # 忽略所有的log文件 *.log# 忽略所有的…...

LeetCode Hot100 搜索二维矩阵

给你一个满足下述两条属性的 m x n 整数矩阵&#xff1a; 每行中的整数从左到右按非严格递增顺序排列。每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target &#xff0c;如果 target 在矩阵中&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。…...

iOS中的KVO(Key-Value Observing)详解

iOS中的KVO&#xff08;Key-Value Observing&#xff09;详解 一、KVO概述 KVO&#xff08;Key-Value Observing&#xff09;&#xff0c;即键值观察/监听&#xff0c;是苹果提供的一套事件通知机制。它允许一个对象&#xff08;观察者&#xff09;观察/监听另一个对象&#…...

算法 —— 暴力枚举

目录 循环枚举 P2241 统计方形&#xff08;数据加强版&#xff09; P2089 烤鸡 P1618 三连击&#xff08;升级版&#xff09; 子集枚举 P1036 [NOIP2002 普及组] 选数 P1157 组合的输出 排列枚举 P1706 全排列问题 P1088 [NOIP2004 普及组] 火星人 循环枚举 顾名思…...

构造+有序集合,CF 1023D - Array Restoration

一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 1023D - Array Restoration 二、解题报告 1、思路分析 先考虑合法性检查&#xff1a; 对于数字x&#xff0c;其最左位置和最右位置 之间如果存在数字比x小&#xff0c;则非法 由于q次操作&#xff0c;第q…...

Scrapy 爬取旅游景点相关数据(四)

本节内容主要为&#xff1a; &#xff08;1&#xff09;创建数据库 &#xff08;2&#xff09;创建数据库表 &#xff08;3&#xff09;爬取数据进MYSQL库 1 新建数据库 使用MYSQL数据库存储数据&#xff0c;创建一个新的数据库 create database scrapy_demo;2 新建数据表 CR…...

Vue常用指令及其生命周期

作者&#xff1a;CSDN-PleaSure乐事 欢迎大家阅读我的博客 希望大家喜欢 目录 1.常用指令 1.1 v-bind 1.2 v-model 注意事项 1.3 v-on 注意事项 1.4 v-if / v-else-if / v-else 1.5 v-show 1.6 v-for 无索引 有索引 生命周期 定义 流程 1.常用指令 Vue当中的指令…...

简化数据流:Apache SeaTunnel实现多表同步的高效指南

Apache SeaTunnel除了单表之间的数据同步之外&#xff0c;也支持单表同步到多表&#xff0c;多表同步到单表&#xff0c;以及多表同步到多表&#xff0c;下面简单举例说明如何实现这些功能。 单表 to 单表 一个source&#xff0c;一个sink。 从mysql同步到mysql&#xff0c;…...

均匀圆形阵列原理及MATLAB仿真

均匀圆形阵列原理及MATLAB仿真 目录 前言 一、均匀圆阵原理 二、圆心不存在阵元方向图仿真 三、圆心存在阵元方向图仿真 四、MATLAB仿真代码 总结 前言 本文详细推导了均匀圆形阵列的方向图函数&#xff0c;对圆心不放置阵元和圆心放置阵元的均匀圆形阵列方向图都进行了仿…...

vue2使用univerjs

1、univerjs Univer 提供了一个全面的企业级文档与数据协同的解决方案&#xff0c;支持电子表格、文本文档和演示幻灯片三大核心文档类型。通过灵活的 API 和插件机制&#xff0c;开发者可以在 Univer 的基础上进行个性化功能的定制和扩展&#xff0c;以适应不同用户在不同场景…...

VUE3 el-table-column header新增必填*

1.在需要加必填星号的el-table-column上添加render-header属性 <el-table-column :label"getName(产品代码)" :render-header"addRedStart" prop"MODELCODE" min-width“4.5%”> <template v-slot"scope"> <el-input …...

条件概率和贝叶斯公式

...

Kali中docker与docker-compose的配置

权限升级 sudo su 升级为root用户 更新软件 apt-get update安装HTTPS协议和CA证书 apt-get install -y apt-transport-https ca-certificates下载docker apt下载docker apt install docker.io 验证docker安装是否成功 查版本 docker -v 启动docker systemctl start …...

C++ | Leetcode C++题解之第283题移动零

题目&#xff1a; 题解&#xff1a; class Solution { public:void moveZeroes(vector<int>& nums) {int n nums.size(), left 0, right 0;while (right < n) {if (nums[right]) {swap(nums[left], nums[right]);left;}right;}} };...

Exponential Moving Average (EMA) in Stable Diffusion

1.Moving Average in Stable Diffusion (SMA&EMA) 1.Moving average 2.移动平均值 3.How We Trained Stable Diffusion for Less than $50k (Part 3) Moving Average 在统计学中&#xff0c;移动平均是通过创建整个数据集中不同选择的一系列平均值来分析数据点的计算。 …...

017、Vue动态tag标签

文章目录 1、先看效果2、代码 1、先看效果 2、代码 <template><div class "tags"><el-tag size"medium"closable v-for"item,index in tags":key"item.path":effect"item.title$route.name?dark:plain"cl…...

RocketMQ 架构概览

Apache RocketMQ 是一个分布式消息中间件和流计算平台&#xff0c;提供低延迟、高性能和可靠的队列服务&#xff0c;并且支持大规模的分布式系统。在详细介绍 RocketMQ 的整体架构之前&#xff0c;先了解其设计目标和核心特性是很重要的。RocketMQ 主要用于处理大规模的消息&am…...

优化医疗数据管理:Kettle ETL 数据采集方案详解

在现代医疗保健领域&#xff0c;数据的准确性、完整性和及时性对于提高医疗服务质量和患者护理至关重要。为了有效管理和利用医疗数据&#xff0c;Kettle ETL&#xff08;Extract, Transform, Load&#xff09;数据采集方案成为了许多医疗机构的首选工具之一。本文将深入探讨Ke…...

spring-from表单

在spring boot当中,from表单怎样开发(name=value) 先列出接口所需信息(抓包得到请求信息),将这些必要信息以注解的方式表达出来 步骤: 梳理前置条件(请求地址,请求header,请求方法,请求数据,响应结果)编辑一个普通类,在类上标记注解@Controller: 标记在类上,让类…...

【.NET】asp.net core 程序重启容器后redis无法连接,连接超时

环境是容器化部署asp.net core 程序当有大量请求打到容器如果此时重启容器会出现&#xff0c;redis无法连接情况。 使用 csredis 库报错&#xff1a; Status unavailable, waiting for recovery. Connect to server timeout 使用StackExchange.Redis 报错&#xff1a; Time…...

【vue前端项目实战案例】Vue3仿今日头条App

本文将开发一款仿“今日头条”的新闻App。该案例是基于 Vue3.0 Vue Router webpack TypeScript 等技术栈实现的一款新闻资讯类App&#xff0c;适合有一定Vue框架使用经验的开发者进行学习。 项目源码在文章末尾 1 项目概述 该项目是一款“今日头条”的新闻资讯App&#xf…...

常见的文心一言的指令

文心一言&#xff0c;作为百度研发的预训练语言模型“ERNIE 3.0”的一项功能&#xff0c;能够与人对话互动&#xff0c;回答问题&#xff0c;协助创作&#xff0c;高效便捷地帮助人们获取信息、知识和灵感。以下是一些常见的文心一言指令类型及其具体示例&#xff1a; 1. 查询…...

数字货币交易接口实现(含源代码)

数字货币交易接口实现&#xff08;含源代码&#xff09; 使用币安交易接口步骤1&#xff1a;注册API密钥步骤2&#xff1a;安装所需库步骤3&#xff1a;使用API进行交易获取市场数据查看账户信息执行交易错误处理安全提示 使用OKX交易接口步骤1&#xff1a;注册API密钥步骤2&am…...

c++函数以及函数分文件编写

1.函数 1.1格式 返回值类型 函数名 &#xff08;参数列表&#xff09;//返回值类型指的是return过去的类型 { 函数体语句 return 表达式 } 1.2常见的函数样式 1.无参返回 2.有参返回 3.无参有返 4.有参有返 #include<iostream> using namespace std; int add(int nu…...

【JVM基础06】——组成-直接内存详解

目录 1- 引言&#xff1a;直接内存概述1-1 直接内存是什么&#xff1f;直接内存的定义(What)1-2 为什么用直接内存&#xff1f;Java程序对直接内存的使用 (Why) 2- ⭐核心&#xff1a;详解直接内存(How)2-1 文件拷贝案例介绍对比常规 IO(BIO) 和 NIO常规 IO 的操作流程NIO 的操…...

学术研讨 | 区块链与隐私计算领域专用硬件研讨会顺利召开

学术研讨 近日&#xff0c;国家区块链技术创新中心主办&#xff0c;长安链开源社区支持的“区块链与隐私计算领域专用硬件研讨会”顺利召开&#xff0c;会议围绕基于区块链与隐私计算的生成式AI上链、硬件加速、软硬协同等主题展开讨论&#xff0c;来自复旦大学、清华大学、北京…...

AngularJS API 深入解析

AngularJS API 深入解析 AngularJS,作为一个强大且灵活的JavaScript框架,自从其诞生以来,就一直是前端开发者构建复杂Web应用的首选工具。本文将深入探讨AngularJS的API,帮助读者理解其核心功能和工作原理。 AngularJS简介 AngularJS由Google开发,并于2010年发布。它是…...

过某开源滑动验证码

过某开源滑动验证码 今天早上我有一点空闲时间&#xff0c;想着回顾一下前几天在某查询网站遇到的滑动验证码&#xff0c;以免时间久了忘记了。那个网站可能使用的是较早版本的开源滑块验证码系统tianai-captcha&#xff0c;但我不确定是否正确。 整体思路&#xff1a; 获取…...

一文解决 | Linux(Ubuntn)系统安装 | 硬盘挂载 | 用户创建 | 生信分析配置

原文链接&#xff1a;一文解决 | Linux&#xff08;Ubuntn&#xff09;系统安装 | 硬盘挂载 | 用户创建 | 生信分析配置 本期教程 获得本期教程文本文档&#xff0c;在后台回复&#xff1a;20240724。请大家看清楚回复关键词&#xff0c;每天都有很多人回复错误关键词&#xf…...

Matlab M_map工具箱绘制Interrupted Mollweide Projection

GMT自带了许多的地图投影&#xff0c;但是对于Interrupted Mollweide投影效果却不好。 作为平替的m_map工具箱中带有的投影类型可完美解决这一问题。 Interrupted Mollweide Projection长这样 全球陆地 全球海洋 使用Matlab工具箱m_map展示全球海平面变化的空间分布 addpath(…...

Python 变量与基本数据类型

重点内容 1 掌握变量及厂里在数据输入、输出及计算中的应用&#xff1b; 2 熟练使用datetime模块来处理日期和时间问题&#xff1b; 3 熟练掌握abs()、round()、pow()、sum()、min()、max()等的应用&#xff1b; 4 利用变量、字符等知识模拟开发中一些场景的输入与输出&…...

Pytorch深度学习实践(5)逻辑回归

逻辑回归 逻辑回归主要是解决分类问题 回归任务&#xff1a;结果是一个连续的实数分类任务&#xff1a;结果是一个离散的值 分类任务不能直接使用回归去预测&#xff0c;比如在手写识别中&#xff08;识别手写 0 − − 9 0 -- 9 0−−9&#xff09;&#xff0c;因为各个类别…...

认识漏洞-GitLab 远程命令执行漏洞、致远OA-ajax.do未授权任意文件上传漏洞

为方便您的阅读&#xff0c;可点击下方蓝色字体&#xff0c;进行跳转↓↓↓ 01 [GitLab 远程命令执行漏洞复现(CVE-2021-22205)](https://mp.weixin.qq.com/s/4QT-vxKpBn4ppNM9ipt-nQ)02 [致远OA-ajax.do未授权任意文件上传Getshell](https://mp.weixin.qq.com/s/TH2A5J5TXU36Y…...

vue实现电子签名、图片合成、及预览功能

业务功能&#xff1a;电子签名、图片合成、及预览功能 业务背景&#xff1a;需求说想要实现一个电子签名&#xff0c;然后需要提供一个预览的功能&#xff0c;可以查看签完名之后的完整效果。 需求探讨&#xff1a;后端大佬跟我说&#xff0c;文档我返回给你一个PDF的oss链接…...

【flink】之如何消费kafka数据?

为了编写一个使用Apache Flink来读取Apache Kafka消息的示例&#xff0c;我们需要确保我们的环境已经安装了Flink和Kafka&#xff0c;并且它们都能正常运行。此外&#xff0c;我们还需要在项目中引入相应的依赖库。以下是一个详细的步骤指南&#xff0c;包括依赖添加、代码编写…...

科研绘图系列:R语言山脊图(Ridgeline Chart)

介绍 山脊图(Ridge Chart)是一种用于展示数据分布和比较不同类别或组之间差异的数据可视化技术。它通常用于展示多个维度或变量之间的关系,以及它们在不同组中的分布情况。山脊图的特点: 多变量展示:山脊图可以同时展示多个变量的分布情况,允许用户比较不同变量之间的关…...

Boost搜索引擎:如何建立 用户搜索内容 与 网页文件内容 之间的关系

如果想使“用户搜索内容”和“网页文件内容”之间产生联系&#xff0c;就应该将“用户搜索内容”和“网页文件”分为很小的单元 &#xff08;这个单元就是关键词&#xff09;&#xff0c;寻找用户搜索单元是否出现在这个文档之中&#xff0c;如果出现就证明这个网页文件和用户搜…...

【QT】QT 窗口(菜单栏、工具栏、状态栏、浮动窗口、对话框)

Qt 窗口是通过 QMainWindow类来实现的。 QMainWindow 是一个为用户提供主窗口程序的类&#xff0c;继承自 QWidget 类&#xff0c;并且提供了⼀个预定义的布局。QMainWindow 包含一个菜单栏&#xff08;Menu Bar&#xff09;、多个工具栏&#xff08;Tool Bars&#xff09;、…...

Golang | Leetcode Golang题解之第283题移动零

题目&#xff1a; 题解&#xff1a; func moveZeroes(nums []int) {left, right, n : 0, 0, len(nums)for right < n {if nums[right] ! 0 {nums[left], nums[right] nums[right], nums[left]left}right} }...

ubuntu22.04 安装 NVIDIA 驱动以及CUDA

目录 1、事前问题解决 2、安装 nvidia 驱动 3、卸载 nvidia 驱动方法 4、安装 CUDA 5、安装 Anaconda 6、安装 PyTorch 1、事前问题解决 在安装完ubuntu之后&#xff0c;如果进入ubuntu出现黑屏情况&#xff0c;一般就是nvidia驱动与linux自带的不兼容&#xff0c;可以通…...

数据结构·AVL树

1. AVL树的概念 二叉搜索树虽可以缩短查找的效率&#xff0c;但如果存数据时接近有序&#xff0c;二叉搜索将退化为单支树&#xff0c;此时查找元素效率相当于在顺序表中查找&#xff0c;效率低下。因此两位俄罗斯数学家 G.M.Adelson-Velskii 和E.M.Landis 在1962年发明了一种解…...

记一次Mycat分库分表实践

接了个活,又搞分库分表。 一、分库分表 在系统的研发过程中,随着数据量的不断增长,单库单表已无法满足数据的存储需求,此时就需要对数据库进行分库分表操作。 分库分表是随着业务的不断发展,单库单表无法承载整体的数据存储时,采取的一种将整体数据分散存储到不同服务…...

数据分析:微生物数据的荟萃分析框架

介绍 Meta-analysis of fecal metagenomes reveals global microbial signatures that are specific for colorectal cancer提供了一种荟萃分析的框架&#xff0c;它主要基于常用的Wilcoxon rank-sum test和Blocked Wilcoxon rank-sum test 方法计算显著性&#xff0c;再使用分…...

Django—admin后台管理

Django官网 https://www.djangoproject.com/ 如果已经有了Django跳过这步 安装Django&#xff1a; 如果你还没有安装Django&#xff0c;可以通过Python的包管理器pip来安装&#xff1a; pip install django 创建项目&#xff1a; 使用Django创建一个新的项目&#xff1a; …...

数字图像处理中的常用特殊矩阵及MATLAB应用

一、前言 Matlab的名称来源于“矩阵实验室&#xff08;Matrix Laboratory&#xff09;”&#xff0c;其对矩阵的操作具有先天性的优势&#xff08;特别是相对于C语言的数组来说&#xff09;。在数字图像处理中&#xff0c;为了提高编程效率&#xff0c;我们可以使用多种方式来创…...