【C++软件调试技术】C++软件开发维护过程中典型调试问题的解答与总结

目录

1、引发C++软件异常的常见原因有哪些?

2、排查C++软件异常的常用方法有哪些?

3、为什么要熟悉常见的异常内存地址?

4、调试时遇到调用IsBadReadPtr或者IsBadWritePtr引发的异常,该如何处理?

5、如何排查GDI对象泄露问题?

6、如何排查内存泄露问题?

7、如何排查死循环(高CPU占用)问题?

8、如何排查数据格式化时的崩溃问题?

9、如何排查堆内存被破坏问题?

10、如何排查线程堵塞或卡死问题?

11、如何排查程序中的资源泄露问题?

12、如何排查第三方库注入引发的异常问题?

13、如何排查库与库之间不匹配问题?

14、如何排查程序启动异常(启动报错、崩溃、卡死)问题?

15、使用Windbg分析软件异常有哪些方式?

16、为什么有的异常捕获不到?

17、常用的开源异常捕获库有哪些?

18、异常捕获库捕获不到异常时,该怎么办?

19、生成dump文件的方式有哪些?

20、为什么要加载pdb文件?为什么要加载系统库的pdb文件?


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/124272585C++软件分析工具从入门到精通案例集锦(专栏文章,持续更新中...)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++软件日常开发和维护中遇到的多个软件调试问题及有代表性的场景,给出详细的处置思路和处理办法,以供大家借鉴和参考!希望大家在了解这些内容以后,能从容地应对开发维护过程中遇到的各种问题。

1、引发C++软件异常的常见原因有哪些?

       引发C++软件异常的常见原因有:访问空指针与野指针、内存越界(栈内存越界、堆内存越界和全局内存越界)、内存访问违例、线程栈溢出、堆内存被破坏、内存泄露、死循环、多线程死锁、待格式化参数与格式化符号不匹配、库与库之间的不匹配等。

       我之前根据多年的C++软件异常排查实践,对这些引发C++软件异常的常见原因进行了详细总结,可查看文章:

引发C++软件异常的常见原因分析与总结(实战经验分享)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/124996473了解这些常见原因之后,我们在排查问题时可能会快速找到可疑点和排查方向,能有限地提高我们排查问题的效率!

2、排查C++软件异常的常用方法有哪些?

       了解引发C++软件异常的常见原因之后,我们还要掌握排查C++软件异常的常用手段与方法。

       排查问题的常用方法有:使用常用工具去辅助分析(比如程序启动失败、启动报错、库加载失败、死循环与高CPU占用问题等)、使用IDE开发工具调试(Debug调试、Release调试和附加到进程调试)、添加打印日志、分块注释代码、数据断点监测内存、历史版本比对法、Windbg分析(静态分析dump文件、动态调试目标进程)、使用反汇编工具IDA查看汇编代码辅助分析等。

       我之前根据多年的C++软件异常排查实践,对这些排查手段和方法进行了详细的总结,可查看文章:

排查C++软件异常的常见思路与方法(实战经验总结)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/120629327掌握这些排查软件异常的常用手段与方法之后,在遇到新的问题时我们的排查思路会更开阔、更高效,必要时需要将多种排查方法结合起来使用。


         在这里,给大家重点推荐一下我的几个热门畅销专栏:

专栏1:(该专栏订阅量已达到420多个,有很强的实战参考价值,广受好评!专栏文章持续更新中,预计更新到200篇以上!)

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

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

专栏中的文章均是通过项目实战总结出来的(通过项目实战积累了大量的异常排查素材和案例),有很强的实战参考价值!专栏文章还在持续更新中,预计文章篇数能更新到200篇以上!

专栏2: 

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

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

专栏3: 

开源组件及数据库技术icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_12458859.html

以多年的开发实战为基础,分享一些开源组件及数据库技术!


3、为什么要熟悉常见的异常内存地址?

       一般我们只需要了解0xcccccccc、0xcdcdcdcd、0xfeeefeee和0xdddddddd这4个内存地址异常值:

当我们调试代码时遇到这些内存地址异常值后,可以大概知道是什么原因引起的,以这个为线索,就可以迅速地分析并定位问题。

        对于0xcccccccc和0xcdcdcdcd,在 debug 模式下,Visual Studio会把未初始化的栈内存全部填充成0xcccccccc,当成字符串看就是“烫烫烫烫……”;Visual Studio会把未初始化的堆内存全部填充成 0xcdcdcdcd,当成字符串看就是 “屯屯屯屯……”。这两类特殊的字符串,很多人应该都见到过。所以在debug调试时遇到有变量的值为0xcccccccc 或0xcdcdcdcd,一般是变量没有初始化引起的。

        对于0xfeeefeee,是Debug下用来标记堆上已经释放掉的内存,即已经释放的堆内存中会被填充成0xfeeefeee。注意,如果指针指向的内存被释放了,指针变量本身的地址是没做改变的,还是其之前指向的内存的地址,只是其指向的堆内存中被填充成0xfeeefeee。

        对于0xdddddddd,是Debug下用来标记堆上已经释放掉的内存,即已经释放的堆内存会被填充成0xdddddddd。0xfeeefeee也是Debug下用来填充已经释放的堆内存,但0xdddddddd和0xfeeefeee的使用场景应该是有区别的,具体区别我也不太清楚。

之前在项目问题中看到的基本都是0xfeeefeee,没见到过0xdddddddd,但前段时间在Debug下调试代码时遇到了,代码中访问了已经释放的内存,内存中都被置为0xdddddddd,这还是第一次遇到0xdddddddd异常值!正是通过0xdddddddd的说明,得知这个0xdddddddd是用来填充已经释放的堆内存,以这个为线索,快速地定位了问题!

        关于上述异常地址的详细说明,可以参见文章:

C++ 中常见异常内存地址的说明(0xcccccccc、0xcdcdcdcd、0xfeeefeee 和 0xdddddddd 等)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/128285918

4、调试时遇到调用IsBadReadPtr或者IsBadWritePtr引发的异常,该如何处理?

       IsBadReadPtr和IsBadWritePtr最开始是为了判断内存地址是否是可读可写的,但这两个API函数已经被官方废弃了,已经不再具有最开始那种判断作用了,强烈建议大家不要再使用这两个API函数!

       一些老的代码中可能还会调用IsBadReadPtr和IsBadWritePtr,比如我们项目中调用了一个第三方的dll库,这个库是好几年前的版本。我是怎么知道第三方库中调用了IsBadReadPtr和IsBadWritePtr函数的呢?看了我接下来说的内容就知道了!

       当代码执行到IsBadReadPtr和IsBadWritePtr函数调用的地方会产生一个异常,如果当前正在调试代码,则会让调试器中断下来。比如我们在用Visual Studio调试代码或者正在使用Windbg动态调试程序,会让调试器Visual Studio或Windbg中断下来。

        程序产生异常,如果在调试状态下,都会让调试器中断下来,怎么知道是调用IsBadReadPtr和IsBadWritePtr的呢?其实很简单,调试器中断下来后直接查看此时的函数调用堆栈就知道了,堆栈中能看到这两个函数的调用。

        当我们使用Visual Studio或者Windbg调试时,代码执行到IsBadReadPtr和IsBadWritePtr调用处,会抛出一个异常,调试器中断下来,没有经验的人以为程序产生崩溃了,其实不然,这个异常是非致命性的,可以跳过去,程序还可以继续运行。

异常根据严重程度可分为致命性异常和非致命性异常。致命性异常是不可恢复的,会导致程序发生崩溃闪退。非致命性的异常,则是可以跳过去的,程序可以继续运行,不会导致程序的崩溃和闪退。

       如果在用Visual Studio调试代码遇到这个异常中断,按下F5可以将异常中断跳过去。如果是在用Windbg调试目标进程,则输入命令g就可以将异常中断跳过去。注意,如果代码中多次调用了IsBadReadPtr和IsBadWritePtr,则需要多次跳过去。

       之前我写过关于IsBadReadPtr和IsBadWritePtr相关案例的文章,需要的话,可以去查看:

使用Windbg排查C++程序调用IsBadReadPtr或IsBadWritePtr引发内存访问违例问题icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/129892952

5、如何排查GDI对象泄露问题?

       所谓的GDI对象泄露,就是GDI对象使用完成后没有释放,导致泄露。在Windows系统中,一个进程的GDI对象总数为1万个,当进程的GDI对象总数接近或达到这个上限,则会导致GDI绘图失败,甚至引发程序崩溃。

       GDI对象泄露在UI程序编程中经常遇到,如果存在GDI对象泄露,在Windows任务管理器中可以看到GDI对象总数在持续的上涨。但任务管理器中看不到具体是哪一种GDI对象在不断增长。可以使用GDIView工具,可以看到给类GDI对象的数目,这样就能看到具体是哪个对象在增长,这样结合代码的修改记录,就能很快定位泄露的地方了。

       之前写过使用GDIView排查GDI对象泄露的分析实例,可以去查看文章:

使用GDIView工具排查GDI对象泄漏导致程序UI界面绘制异常的问题icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/128625868

6、如何排查内存泄露问题?

       所谓的内存泄露就是动态申请的内存,在使用完后没有去释放,导致泄露。内存泄露在C++程序中比较常见。

       对于大型项目,代码量比较大,业务复杂,内存泄露排查起来会比较费劲!有多个工具和方法去排查,比如可以使用Windbg中的umdh. exe工具、使用Windbg中的堆内存信息查看命令、使用Visual Leak Detector工具、甚至使用Visual Studio 2019开始集成的google出品的专用内存分析工具AddressSanitizer。此外像BounderCheck这种老的工具,若干年前就已经停止维护了,已经不支持新版本的Visual Studio了,也就没法使用了。

       有时有的内存泄露问题,很难排查,用一个工具和方法分析不出来,可以多尝试几个工具和方法,直到分析出来为止!

       使用Visual Leak Detector(简称VLD)排查内存泄露的案例文章:

​ 使用Visual Leak Detector排查内存泄漏 icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/135472681 ​       使用其他工具分析内存泄露的案例,可以查看内存泄露专栏中的文章:

​ C++内存泄漏排查专题icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_12370029.html ​

7、如何排查死循环(高CPU占用)问题?

       代码中发生了死循环,一直在执行循环体中的代码,会有一个典型的现象,进程的CPU占用会比较高。

       为什么死循环会导致CPU占用高的问题呢?其实很好理解,因为代码一直在不停歇地执行循环体中代码,一直在占用CPU时间片,所以导致CPU占用高。其实是表现为进程中的某个线程占用的CPU高,因为死循环的代码是执行在某个线程中的,所以这个线程占用的CPU高。

        这种死循环问题排查起来很简单,先用Process Explorer查看哪个线程占用CPU高。然后将Windbg附加到进程上,然后通过占用CPU高的那个线程的id,在windbg中切换到该线程中,输入kn命令查看该线程当前的函数调用堆栈,然后对照着代码就能确定发生死循环的代码位置了。在Process Explorer中也可以查看函数调用堆栈,但看的不准确,并且有时要看相关变量的值去确定为什么发生死循环,这些只能在Windbg中查看,在Process Explorer中是查看不到的。

       我之前写过使用Process Explorer和Windbg排查死循环的案例,可以查看文章:

使用Process Explorer/Process Hacker和Windbg高效排查软件高CPU占用问题icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/135822428

8、如何排查数据格式化时的崩溃问题?

        一般我们在打印日志时需要将相关变量的值格式化到字符串中,然后将字符串打印出来。在格式化时,时常会用到遇到异常崩溃问题。

        一种最简单的场景是,待格式化参数与对应的格式化符不匹配导致了异常。比如一个int类型的参数,却使用了%s的格式化符,比如:

int i = 1;
char szBuf[256] = { 0 };
sprintf( szBuf, "%s", i );

格式化函数内部会去解析出设置的格式化符,然后到栈上传过来的对应位置的待格式化参数。格式化函数解析到%s,到栈上拿到对应的参数,然后把参数值与%s对应,即把参数值当成字符串首地址来处理,在此示例代码中,把参数i的值1,当成字符串首地址,即到 0x00000001地址的内存中把字符串读出来去格式化,而这个0x00000001地址值很小,属于64KB的小地址内存区(空指针地址内存区),这个区域的内存是禁止访问的,所以产生了内存违例,引发崩溃。

        这种场景下问题排查很简单,只要看看格式化符与待格式化参数是否匹配即可发现问题。一般这类问题,可能是写代码时手误,讲格式化符号用错了。

       还有一类场景隐藏的比较深,本质上也是格式化符与待格式化参数类型不匹配的问题。比如一个int64的参数,却使用了32位整型对应的%d,导致格式化函数内部再从栈上取对应位置的数据(传入被调用函数的参数是压到栈上传递过来的)时取的数据长度有问题,导致格式化符取数据错位问题,可能会引发崩溃。这类问题一般很难一眼看出来,之前我就帮同事排查过一个类似的问题,详细分析排查过程可以见文章:

UINT64整型数据在格式化时使用了不匹配的格式化符%d导致其他参数无法打印的问题排查icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/132549186

9、如何排查堆内存被破坏问题?

       堆内存被越界破坏,是最难查的一类内存问题。当堆内存被破坏时,程序会到处“乱崩溃”,一会崩溃在这里,一会崩溃在那里,有时崩溃在new一个对象或一段内存地方,有时崩溃在delete对象或内存地方。

       为啥会出现胡乱崩溃的问题呢?因为越界将堆内存头部或尾部区域给篡改了,而系统管理堆内存就是通过头部和尾部的信息来管理的,一旦被篡改,导致堆内存管理出问题,导致后续申请或释放堆内存产生异常。

       堆内存被破坏,排查起来比较困难,Windows平台上没有专用的内存检测工具,只能通过注释代码逐步缩小排查范围去查。而Linux平台上则有专用的内存检测工具Valgrind和AddressSanitizer。好在Visual Studio 2019 19.6以后的版本引入了google的AddressSanitizer,大家后面遇到问题可以试用一下。因为我们项目组从上到下统一使用的是Visual Studio 2017,所以不能使用。

       以前项目中遇到一个内存越界篡改堆内存头信息导致delete去释放堆内存时产生了异常,相关文章如下:

C++堆内存错误:C运行时库检测到向堆内存头部写入了内容icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/121800292

10、如何排查线程堵塞或卡死问题?

       一般线程堵塞或卡死可能是两个原因导致的,一个是多线程之间发生了死锁,一个是线程中发生了死循环。一旦线程发生堵塞,线程相关的业务没法顺利执行,导致软件业务出现异常。

       对于死循环问题的排查,上面已经讲过了。对于多线程死锁,如果是临界区死锁,也可以在Windbg中查看发生死锁的临界区锁信息,可以快速地定位。如果是非临界区锁,排查起来比较麻烦,可以将所有线程的函数调用堆栈都打印出来,然后结合代码,判断出哪个线程发生了死锁。一般添加打印日志,也能辅助定位死锁发生的位置。

       对于使用Windbg分析临界区死锁问题,可以查看我以前写的文章:

使用Windbg分析多线程临界区死锁问题分享icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/128532743

11、如何排查程序中的资源泄露问题?

        程序中的GDI对象泄露、内存泄露和句柄泄露,都属于资源泄露。GDI对象泄露和内存泄露比较常见,我上面已经详细的讲解了。对于句柄泄露,我们在项目中遇到过,代码中频繁创建线程,任务很快执行完线程退出,但没有关闭线程句柄,导致后续创建线程失败,业务出现异常。

        对于资源泄露,之前写了专题文章,可以查看:

深入探究 C++ 程序中的资源泄漏问题icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/133631728

12、如何排查第三方库注入引发的异常问题?

       有些第三方程序(比如输入法和安全软件)会有模块注入到我们的程序进程中,可能会导致我们的程序出现异常。我们在项目中遇到过几次。

       对于输入法注入,输入法之所以能支持在所有程序中输入文字,是因为他有专门的注入模块,会注入到所有的进程中。到这种注入可能会引发异常,比如会导致软件时不时的卡顿,导致软件发生死锁,我们在项目中遇到过。对于死锁,我们在Windbg显示的发生死锁的那个线程的函数调用堆栈中看到了输入法的模块,正因为输入法接口调用触发的!

        对于第三方安全软件注入,第三方安全软件就是通过注入到进程中对进程进行监控的。如果注入模块发生内存泄露或者崩溃,会直接影响到我们的软件进程,因为它位于我们的进程空间中!这个我们在项目中都遇到过,相关文章可以查看:

第三方模块远程注入到软件中引发软件异常的若干实战案例分享icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/134545223

13、如何排查库与库之间不匹配问题?

        库与库之间的不匹配,一般是两个库的版本不一致。可以从头文件的角度去看(底层发布库到我们的软件中),比如只更新了API头文件但库没更新库文件,再比如只更新了库文件却没有更新API头文件。API头文件中可能有相关结构体的定义,比如新版本中修改了结构体成员(删除或新增了成员),库的版本不匹配也可能会出问题。

        比如A库依赖B库,A库中调用了B库的接口,A库编译时用到B库的API头文件b. h。编译A库时,因为调用 B库的接口,所以要依赖B库的API头文件b. h。而B库本身编译时,一会依赖其API头文件b. h。如果A库使用的B库与B库的头文件b. h版本不一致,也可能会出问题,编译可能没问题,但运行时可能会出问题。

       当软件出现崩溃时,分析函数调用堆栈时也看不出问题,这时可能是库与库不匹配导致的。根据函数调用堆栈中模块,查看这些模块及头文件在svn上的发布记录(假设库是底层模块开发组打不过来的),并与模块的维护人员确认是否是库的版本问题。

14、如何排查程序启动异常(启动报错、崩溃、卡死)问题?

        程序启动时,系统会先把exe程序依赖的所有dll库加载到程序的进程空间中,最后才会进入exe主程序的main函数,程序才能运行起来。

       如果依赖的库,在电脑系统中找不到,则程序启动时会报缺少库的提示,一般是因为程序打包(生成安装包)忘记把缺少的库打包进安装包导致的。把缺少的库打包进去即可。

       如果程序调用的接口在对应的库找不到,程序启动时会报在某个库找不到接口(可能接口名称边了,也可能是接口参数变了),此时可以用Dependency Walker打开exe主程序文件,看看具体是哪个模块调用了这个接口,确认一下是主调模块有问题,还是被调模块有问题。

       如果是启动过程中发生崩溃,可能是加载某个库时库的初始化代码有问题引发的,程序发生崩溃闪退。这时没有机会将Windbg附加到进程上去分析,因为程序已经崩溃闪退了。此时可以使用Windbg将程序启动起来,一旦程序发生崩溃,Windbg就会感知到,就会中断下来,就可以去分析了。

      《C++软件调试与异常排查从入门到精通》专栏中有专门的章节讲述程序启动异常排查的专题,感兴趣的朋友可以去查看:

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

15、使用Windbg分析软件异常有哪些方式?

       Windbg排查软件异常主要有两种方式,即静态分析dump和动态调试目标进程。当我们有dump文件时,则使用静态分析dump文件的方式。如果没有生成dump文件(可能没捕获到异常),或者从现有的dump文件中分析不出问题时,可以将Windbg附加到目标进程上进行动态调试。

       使用Windbg静态分析dump文件的一般步骤,见文章:

使用Windbg静态分析dump文件的一般步骤详解icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/135484682       使用Windbg动态调试目标进程的一般步骤,见文章:

使用Windbg动态调试目标进程的一般步骤详解icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/135484906

16、为什么有的异常捕获不到?

       应该是程序中只是简单使用API函数SetUnhandleExceptFilter设置异常回调函数去捕获异常,但这种做法是与线程关联的,需要每个线程都设置回调。只在上层模块中调用设置,只作用所在的线程中的,一般无法捕获其他线程中的异常。而进程中包含了多个模块多个线程,所以其他线程中的异常捕获不到。所以会遇到很多时候捕获不到异常的问题。

       只是简单地调用SetUnhandleExceptFilter设置异常回调去捕获异常,是远远不够的!一般我们使用开源的异常捕获库去捕获异常,比如CrashRpt、BreadPad和CrashPad。

17、常用的开源异常捕获库有哪些?

       常见的开源捕获库CrashRpt、BreadPad和CrashPad。其中CrashRpt是Google早期开源的,但通过项目实战发现该库有些时捕获不到发生的异常,才看代码研究其实现机制发现,她是通过将加载模块导入表中创建线程的CreateThread函数hook成自定义的函数,在该函数中给当前线程设置异常回调函数去实现该线程的异常捕获。但只对在异常捕获模块之前加载的模块进行hook,后加载到进程空间中的模块没有hook,所以后加载模块如果发生异常,是捕获不到的。

       后来我们使用了微软开源的detours项目对CrashRpt进行改进,有效地提高了捕获异常的几率。BreadPad是Google开源的Chrome浏览器中的异常捕获模块,最新版本浏览器中已经改为CrashPad。CrashPad默认是支持Windows的,如果用在linux中,则需要使用Linux版本。

18、异常捕获库捕获不到异常时,该怎么办?

       大家在实际项目中会发现,即使使用了开源的异常捕获库(或者经过升级改造的捕获库),有少部分异常还是捕获不到的

       对于捕获不到的异常,则只能将Windbg附加到目标进程上,和目标进程一起跑,一单进程发生异常,会投递给正在附加调试的Windbg,Windbg就会感知到异常并中断下来,就可以直接在Windbg中分析了。如果一时半会看不出来,可以使用. dump命令将异常上下文导出到dump文件中,事后再去静态分析。

       在正在调试的Windbg中使用命令导出的dump文件,属于全dump文件,文件大小接近进程的虚拟内存的大小。Windbg动态调试相对于静态分析,可以多次go多次动态查看函数调用堆栈,还可以添加断点进行断点调试。

19、生成dump文件的方式有哪些?

       生成dump文件的方式主要有三种。

       最常用的方式是通过异常捕获库去自动生成,即异常捕获库捕获到了软件中发生的异常,自动调用系统API函数MiniDumpWriteDump将异常上下文信息保存到dump文件中。

       也可以从Windows任务管理器中导出进程的dump文件。它用在什么场合下呢?比如程序发生异常弹出保存提示框,此时进程还在的,可以导出dump文件。再比如程序发生死循环或死锁时,进程还在的,也可以从任务管理器中导出dump文件。

       还可以从正在调试的Windbg中使用. dump命令导出dump文件。比如我们在使用Windbg动态调试目标进程时,如果一时半会分析不出问题或者出问题的电脑别人还要用(我们不能长时间占用别人的电脑去分析问题),可以导出dump文件,然后事后去分析dump文件即可。

       关于生成dump文件方式的详细说明,可以参见文章:

dump文件类型与dump文件生成方法详解icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/127991002

20、为什么要加载pdb文件?为什么要加载系统库的pdb文件?

       pdb文件中包含函数及变量的符号信息,加载pdb后在函数调用堆栈中才能看到具体的函数名和代码行号。有时我们需要在Windbg中查看函数中相关变量的值,变量的值可能是关键线索,有pdb中的变量符号才能识别变量,才能看到变量的值。

       pdb文件分软件业务模块的pdb文件和Windows系统库pdb文件。业务模块的pdb需要加载,有时为了搞清楚问题,也要加载系统库pdb的,加载后可以看到系统库中具体调用了哪些接口,可能能找到更为直接的线索。加载pdb后,可能能看到更多行的函数调用,更便于分析问题。

       对于Windows系统库的pdb文件,不需要下载,微软提供了一个在线pdb符号服务器,只需要将这个在线地址设置给Windbg,Windbg在需要时会自动去下载。

       此外,不仅仅Windbg会用到pdb文件,有些分析工具也会用到。比如Process Explorer/Process Hacker、Process Monitor,使用这些工具分析问题时有时需要看函数调用堆栈,需要pdb中的函数符号。再比如使用反汇编工具IDA查看二进制文件的汇编代码,也需要使用到二进制文件的pdb文件中的函数与变量符号。

       关于pdb符号文件的详细说明,可以参见文章:

pdb符号文件详解icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125508858

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

极大似然估计、最大后验估计、贝叶斯估计

机器学习笔记 第一章 机器学习简介 第二章 感知机 第三章 支持向量机 第四章 朴素贝叶斯分类器 第五章 Logistic回归 第六章 线性回归和岭回归 第七章 多层感知机与反向传播【Python实例】 第八章 主成分分析【PCA降维】 第九章 隐马尔可夫模型 第十章 奇异值分解 第十一章 熵…

Flask框架——安装与第一个应用

安装 Flask是一个轻量级的Python Web框架。它是一个微型框架,具有灵活性和可扩展性。Flask使用Python语言编写,它是一个开源框架,使得它可以自由地使用和修改。Flask框架可以用于构建任何类型的Web应用程序,包括单页面应用程序、…

C#硬件接口开发------一文了解WMI

🎈个人主页:靓仔很忙i 💻B 站主页:👉B站👈 🎉欢迎 👍点赞✍评论⭐收藏 🤗收录专栏:C# 硬件接口开发 🤝希望本文对您有所裨益,如有不足…

C++11 设计模式0. 设计模式的基本概念,设计模式的准则,如何学习设计模式,24种设计模式的分为3大类

一 设计模式的基本概念: 模式:指事物的标准样式 或者 理解成 针对特定问题的可重用解决方案。 设计模式,是在特定问题发生时的可重用解决方案。 设计模式一般用于大型项目中。 大型项目中,设计模式保证所设计的模块之间代码的灵…

【Web】设置默认浏览器

专栏文章索引:Web 有问题可私聊:QQ:3375119339 目录 一、步骤 一、步骤 打开 “控制面板” 查看方式选择 “大/小图标” 点击 “默认程序” 点击想要设置的 默认浏览器 点击 “设置默认值” 设置 “默认文件类型”

FreGS:具有渐进频率正则化的3D高斯溅射

FreGS: 3D Gaussian Splatting with Progressive Frequency Regularization FreGS:具有渐进频率正则化的3D高斯溅射 Jiahui Zhang1  Fangneng Zhan2  Muyu Xu1  Shijian Lu1  Eric Xing3, 4 张家慧 1 詹方能 2 许慕玉 1 卢世坚 1 邢志伟 3, 4 1Nanyang Technolo…

调度:setTimeout 和 setInterval

有时我们并不想立即执行一个函数,而是等待特定一段时间之后再执行。这就是所谓的“计划调用(scheduling a call)”。 目前有两种方式可以实现: setTimeout 允许我们将函数推迟到一段时间间隔之后再执行。 setInterval 允许我们重…

Jmeter-跨线程传参(正则提取多个参数、jsonpath提取器)

目的: 当前接口请求的参数依赖于其他请求,且两个请求不是在同一个线程组时就会用到该方法进行跨线程组传参。 实际使用场景: 多个线程组的请求都依赖登录接口,但是登录接口仅执行一次。 实现方法: 以下举例的有正…

25. 【Android教程】列表控件 ListView

在学习了 ScrollView 及 Adapter 两节内容之后,大家应该对 ListView 有了一些基本的了解,它是一个列表样式的 ViewGroup,将若干 item 按行排列。ListView 是一个很基本的控件也是 Android 中最重要的控件之一。它可以帮助我们完成多个 View 的…

bugku-web-需要管理员

页面源码 <html> <head> <meta http-equiv"Content-Type" content"text/html; charsetUTF-8"> <title>404 Not Found</title> </head> <body> <div idmain><i> <h2>Something error:</h2…

指针的深入理解(七)

指针的深入理解&#xff08;七&#xff09; 个人主页&#xff1a;大白的编程日记 个人专栏&#xff1a;C语言学习之路 感谢遇见&#xff0c;我们一起学习进步&#xff01; 文章目录 指针的深入理解&#xff08;七&#xff09;前言一.常量字符串指针1.1常量字符串的理解1.2常量…

[蓝桥杯 2019 国 B] 解谜游戏

[蓝桥杯 2019 国 B] 解谜游戏 题目背景 题目描述 小明正在玩一款解谜游戏。谜题由 24 24 24 根塑料棒组成&#xff0c;其中黄色塑料棒 4 4 4 根&#xff0c;红色 8 8 8 根&#xff0c;绿色 12 12 12 根 (后面用 Y 表示黄色、R 表示红色、G 表示绿色)。初始时这些塑料棒排…

LangChain初学者指南

自从ChatGPT发布以来&#xff0c;大语言模型(LLM)得到极大普及。虽然大多数人没有足够资金和计算资源从头开始训练LLM&#xff0c;但仍然可以基于预训练的LLM来构建一些很酷的东西&#xff0c;例如: 可以根据个人数据与外界互动的个人助理为特定目的定制的聊天机器人对文档或代…

蚂蚁云科技集团正式发布以正教育大模型,专注因材施教

4月12日,蚂蚁云科技集团成功举办“智以育人、慧正无界——以正教育大模型产品发布会”,该产品致力于智慧教育变革,让因材施教成为可能。 上海科学技术交流中心科技企业服务处处长陈霖博士、中国信通院华东分院院长廖运发、上海市科协常委马慧民博士等出席并致辞;南威软件集团执…

设计模式之大话西游

8年前深究设计模式&#xff0c;现如今再次回锅&#xff5e; 还是大话设计模式 这本书还是可以的 大话西游经典的台词&#xff1a;“曾经有一份真挚的爱情摆在我面前,我没有珍惜,等我失去的时候,我才后悔莫及,人世间最痛苦的事莫过于此。如果上天能够给我一个再来一次的机会,我会…

Java多线程的线程状态和线程池参数

一、线程状态 当线程被创建并启动以后&#xff0c;它既不是一启动就进入了执行状态&#xff0c;也不是一直处于执行状态。线程对象在不同的时期有不同的状态。Java中的线程状态被定义在了java.lang.Thread.State枚举类中&#xff0c;State枚举类的源码如下&#xff1a; publi…

轻量级的Spring Cloud Gateway实践,实现api和websocket转发

当国内大部分都是粘贴复制一些重型框架时&#xff0c;有没有人会想到&#xff0c;我们自己做一个小项目&#xff0c;几个小的Spring boot的项目时&#xff0c;我们是否还需要按部就班的用我们公司中用到的Nacos&#xff0c;这种冗余且调配复杂的组件呢&#xff1f; 不是本人说…

软考报考指南

目录 了解软考 选择报考级别与专业 关注报考时间 完成报名手续 准备考试 参加考试 查询成绩与领取证书 了解软考 官网链接&#xff1a;中国计算机技术职业资格网 软考&#xff0c;即计算机技术与软件专业技术资格&#xff08;水平&#xff09;考试&#xff0c;是由国家人…

广州网站建设如何吸引用户眼球

随着互联网技术的发展&#xff0c;现在广州的大多数企业或品牌都会打造高质量的网站&#xff0c;以便更好地宣传&#xff0c;在网站建设过程中&#xff0c;前端网站设计至关重要&#xff0c;主要体现在排版和布局上&#xff0c;高大尚的网站建设并不是将所有模块内容堆放在首页…

中仕公考:教师招聘和事业单位联考的区别

教师招聘考试与事业单位联考作为两种不同的职业资格考试&#xff0c;其在报考条件和考试内容上存在明显的差异&#xff0c;具体内容为大家简要介绍一下&#xff1a; 一、报考条件 1. 教师招聘考试&#xff1a;此类考试的报名通常要求申请者持有相关教师资格证明。对于非师范生…