最平凡日子 最卑微梦想

vs2022调试笔记

本文并非教程,算是一个清单,调试遇到麻烦可以来看看如下方法,或许可以提高debug效率。

解决方案配置

可以配置多个项目之间启动顺序、启动依赖关系、是否开启调试

配置属性->调试->命令参数,可以传入char* argv的参数

设置运行时库MD_MT去掉运行时依赖MSVCP动态库

项目属性->配置属性->C/C++->代码生成->运行库

可以设置为多线程DLL(/MDd)单线程DLL(/MTd),从而设置运行时软件依赖项。

函数断点

可以在没有源码的情况下,设置函数断点,可以看到什么时候调用,参数是什么。

同时可以控制重载函数进入断点。在新建断点处,加上函数名和重载函数参数,可以控制进入断点。

总之这些情况都是在使用其他第三方库时,无法取到源码的情况下。

数据断点监控内存值更改

  1. 添加数据中断
    自动变量 右键当值更改时中断。断点界面,选择新建数据断点
  2. 设罝数据监控起始地址
    直接写内存地址或者表达式是地址
  3. 设置监控的字节数
    64位指针类型是8个字节
    设置完数字断点,会转成内存地址,第二次调试不一定有交

多线程调试代码准备和源码中显示线程运行位置

总之就是调试状态点击暂停后,可以在调试操作栏点击在源中显示线程,可以看到线程运行位置。

并行监视和并行堆栈同时监视多线程的变量

在并行堆栈窗口可以看到多个线程的堆栈,并可以同时监视多个线程代码运行位置.

调试->并行监视,可以看到多线程运行中的变量值,变量值可以增加删除,也可以监视表达式。

标记线程和查看所有线程运行位置

调试->线程里打开线程窗口,可以标记线程,在调试操作栏点击在源中显示线程,可以看到线程运行位置。可以设置分组以及标记系统线程和代码线程。

可以在并行监视窗口标记线程,然后在线程窗口仅关注标记过的线程。

目的是缩小查找出问题的线程的范围,逐步发现问题所在。

条件断点使用线程号筛选进入断点的线程

设置条件断点,把条件设为筛选器,可以设置变量暂存需要筛选的线程号,并且可以设置条件表达式,筛选出符合条件的线程。

通过全部中断和线程列表定位出错代码

在调试操作栏点击全部中断,可以中断所有线程。此时看每次线程都卡在哪里,哪里就发生了死锁。

如何查明指针是否损坏了内存地址

在断点窗口新建一个数据断点,取需要观测的变量的地址,设置为更改时触发。

int main(){
    char buf[16]="test practice ";
    char* ptr = buf;
    int i = 100;
    std::cout<<"i = "<<std::endl;

    //监控i数据,设置数据断点
    memset(ptr, 1, 256);
    std::cout<<"i = "<<std::endl;
    return 0;
}

数组 buf 的长度只有16字节,而 memset 函数试图填充256字节,这会导致缓冲区溢出,产生未定义行为。这可能会覆盖 i 的值及其他未定义的行为。

正确代码如下:

int main(){
    char buf[16]="test practice ";
    char* ptr = buf;
    int i = 100;
    std::cout << "i = " << i << std::endl;

    //修改缓冲区处理长度,避免溢出
    memset(ptr, 1, sizeof(buf));
    std::cout << "i = " << i << std::endl;
    return 0;
}

函数调用很多次_在失败那次进入_断点命中次数

这个在加载场景时,经常遇到,在加载场景时,加载资源时,会调用很多次函数。

或者多个实验中,某一次实验失败。

同时多次渲染,也会调用很多次函数。

断点窗口里,可以修改命中次数,在这里可以设置第几次命中或者调用失败。

函数被调用次数很多,如何在调用失败那次进入断点?
    1 调用几百次才出错,不确定条件
    2 通过断点命中次数,确定第几次失败,例如命中323次,第324次失败
    3 在函数开头设置断点,设置条件断点命中次数为324次

使用内存快照检查内存泄漏

内存快照部分,可以看到内存是否一直上升,且定位到一直上涨的代码。

使用内存快照检查内存泄漏
诊断工具->内存使用率->堆分析

截取快照

其实这里还可以快照cpu使用情况,可以查看哪一个函数占用cpu高,从而定位到代码,优化具体函数或逻辑,可挖掘空间很大。