- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
在C/C++程序开发过程中,开发者受益于C/C++的强大,与此同时也承受着C/C++程序开发的额外风险。像Java、C#这类带GC(内存垃圾回收)的编程语言,在内存管理方面,给开发者提供了“保姆级”的封装,开发者不用太关注内存泄漏问题[1]。但是C/C++的哲学是把更多的控制权交给了开发者,在给了开发者更多的自由的同时,也要求开发者承担更多的责任.
C/C++程序的常见风险之一,就是内存泄漏[2]问题。如果(缺乏经验的,或者大意的)开发者对指针、内存的操作不当,容易引起内存泄漏、缓冲区溢出等问题,轻则造成程序预期之外的运行缺陷,重则被攻击者作为漏洞加以利用,造成网络安全问题.
内存泄漏的问题一旦发生,问题的定位往往比较困难,所以有经验的工程师总结出了解决内存泄漏问题的“黄金法则”,就是“越早发现,越好定位”。比如说,如果程序的上一个版本并不存在显式的内存泄漏问题,然后刚才开发者进行了一个小小的改动,结果发生了内存泄漏,那么内存泄漏问题的根源(Root cause)极有可能就在刚才的那部分代码更改中。如果开发者立即发现了内存泄漏问题,然后马上怀疑到这部分代码变动,进行范围较小的排查,通常能够比较快地发现和解决内存泄漏问题。但如果开发者没有及时发现内存泄漏的发生,继续进行后续的开发,在进行了好几轮代码迭代之后才发现存在内存泄漏问题,此时要想再找出内存泄漏的根源并予以解决,很显然难度要大得多.
所以在C/C++程序开发过程中,有效地监测内存泄漏的发生,常常是一项必须被满足的技术需求。所以就诞生了许多内存泄漏检测工具.
当然,工具永远不能取代有经验的开发者。掌握RAII之类的程序设计原理和技巧,在写代码的过程中就避免内存泄漏等问题(而不是先“写Bug”再“解Bug”),是每一位C/C++开发者的基本职业修养之一.
针对不同的软件运行平台,有不同的内存泄漏检测工具可以选择。比如说,在Linux操作系统平台上知名的内存泄漏检测工具有 Valgrind、Memleax 等,在Windows操作系统平台,有Deleaker、VLD(Visual Leak Detector)等工具.
本文针对Windows操作系统平台上最好用的内存泄漏检测工具:VLD。其它的工具,要么相比VLD来说使用更繁琐,要么要收费(而且费用还不便宜,比如Deleaker),要么又繁琐又贵,但VLD实属一股清流,好用还免费.
VLD官方的版本目前停留在2.5.1[3],发布日期是2017年10月17日,支持Windows 10,其VS插件支持到Visual C++ 2015。网址是:https://kinddragon.github.io/vld/ 。
广大开发者当然不甘心 VLD 就停留在 2.5.1 版本,所以,在 github 上,有另外一个分支的VLD,目前最高稳定版本是 2.7.0,发布于2021年9月13日。其插件支持 Visual C++ 2019 16.7.5.
那么 Visual Studio 2022(Visual C++ 17)就没有VLD的插件支持了,怎么办呢?
实际上使用VLD不需要依赖于它的VS插件。本文接下来介绍的方法,就是不依赖VLD的插件,在Visual C++ 2022开发环境中使用VLD。实际上由于不依赖IDE的插件,所以本文介绍的方法适用于在Windows平台任意开发环境中使用VLD[4],哪怕将来出现了VS2023、VS2024,本文的方法也同样适用.
VLD 2.7.0版的安装文件如图 2-1 所示。 图 2-1:VLD 2.7.0版的安装文件 。
如图 2-2 所示,安装VLD到建议的目录:D:\App\Dev\VLD\v2.7.0 图 2-2:安装VLD到指定路径 。
如图 2-2 所示,VLD安装后,在安装目录中生成了以下3个文件夹,见表 2-1。我们在应用VLD的过程中,仅仅和这3个文件夹里的文件打交道。 表 2-1:VLD安装目录的子目录说明 。
序号 | 文件夹名称 | 说明 |
---|---|---|
1 | include | 使用VLD所需的C语言头文件所在文件夹 |
2 | lib | 隐式调用(静态加载)VLD的动态链接库所需的导入库 |
3 | bin | VLD的动态链接库 |
include子目录中包括调用VLD动态链接库所需的所有头文件。 图 2-3:include子目录 。
lib子目录中包括隐式调用(静态加载)VLD的动态链接库所需的导入库vld.lib.
图 2-4:lib目录整理 。
如图 2-4 所示,将lib子目录中的Win64文件夹重命名为x64.
bin子目录中包含VLD的动态链接库vld_*.dll[5],以及动态链接库运行时涉及到的 “.pdb[6]” 文件和依赖的动态库dbghelp.dll[7].
图 2-5:bin目录整理 。
安装好VLD之后,为了能够方便地使用VLD,进行相关环境变量设置.
图 2-6:设置VLD相关的环境变量 。
如图 2-6 所示,在系统环境变量中新建环境变量VLD_Root,变量值设置为VLD的安装路径,即:D:\App\Dev\VLD\v2.7.0 。
通过宏定义,使得程序在Debug模式下调用VLD进行内存泄漏检查。在Release模式下,不调用VLD[8].
使用VLD的方法如下所述,一共包括3步:
如图 3-1所示,在 MSVC 的 C/C++ 工程属性中,针对All Configurations和All Platforms,设置 C/C++ | General | Additional Include Directories,增加:
$(VLD_Root)\include
图 3-1:引入VLD的头文件所在路径 。
如图 3-2,在MSVC的C/C++工程属性中,针对Configuration: Debug和All Platforms,设置Linker | General | Additional Library Directories,增加:
$(VLD_Root)\lib\$(Platform)
图 3-2:引入VLD导入库所在路径 。
如图 3-3,在MSVC的C/C++工程属性中,针对Configuration: Debug和All Platforms,设置 Linker | Input | Additional Dependencies,增加:
vld.lib
图 3-3:引入VLD导入库 。
如图 3-4,在MSVC的C/C++工程属性中,针对Configuration: Debug和All Platforms,设置Build Events | Post-Build Event | Command Line,增加:
COPY "$(VLD_Root)\bin\$(Platform)\*.*" "$(TargetDir)"
图 3-4:拷贝VLD动态链接库到生成目录 。
在C/C++应用程序的任意一个源码文件中引入一次vld.h,即可实现对VLD的调用。通常的做法是在main函数所在程序源码文件中引入vld.h。显而易见,对vld.h的引用当前仅当Win32平台(Windows操作系统)平台、Debug编译模式的运行时有效.
如代码 3-1 所示,这是一个最简单的C语言应用程序的源码.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
printf("Hello from console application.\n");
return EXIT_SUCCESS;
}
代码 3-1:示例:一个最简单的C语言应用程序的源码 。
以上程序尚未加入对VLD的调用,我们编译出它的x64|Debug版本并运行,如图 3-5 所示,该运行结果用来对随后加入VLD调用之后的运行结果进行对比.
图 3-5:运行结果1 。
现在我们在中代码 3-1 增加对 VLD 的引用,如代码 3-2 所示.
#include <stdio.h>
#include <stdlib.h>
#if defined(_WIN32) && defined(_DEBUG)
#include <vld.h>
#endif
int main(int argc, char* argv[])
{
printf("Hello from console application.\n");
return EXIT_SUCCESS;
}
代码 3-2:调用 VLD 。
由代码 3-2 可知:在程序源码中加入对VLD的调用,仅仅需要引用VLD的头文件<vld.h>即可。为了将对<vld.h>的引用限定在Win32平台(Windows操作系统)平台、Debug编译模式,我们用宏定义进行了限定,如代码 3-3 所示。程序源码其它部分不需要作任何更改.
#if defined(_WIN32) && defined(_DEBUG)
#include <vld.h>
#endif
代码 3-3:引用<vld.h> 。
我们编译出它的x64|Debug版本并运行,如图 3-6 所示: 图 3-6:运行结果2 。
对比图 3-5 和图 3-6 的两个运行结果,易知在增加了代码 3-3 中对<vld.h>的引用之后,VLD监视了程序的运行过程,并未发现任何内存泄漏.
现在我们在代码 3-1 中增加一处显而易见的内存泄漏,如代码 3-4 所示,然后观察运行结果的变化.
#include <stdio.h>
#include <stdlib.h>
#if defined(_WIN32) && defined(_DEBUG)
#include <vld.h>
#endif
int main(int argc, char* argv[])
{
int x = 0;
char* p = NULL;
x++;
p = malloc(1);
x--;
printf("Hello from console application.\n");
return EXIT_SUCCESS;
}
代码 3-4:增加显而易见的一处内存泄漏 。
在代码 3-4 中,我们在第14行代码中申请了1个字节的堆上内存空间,但整个程序直到运行结束前并未对该内存申请进行释放,很显然,这样就造成了1个字节的内存泄漏。现在我们编译出它的x64|Debug版本并运行,观察在VLD的帮助下,能否发现此处内存泄漏。运行结果如图 3-7 所示。 图 3-7:运行结果3:发现了1处内存泄漏 。
如图 3-7 所示,VLD发现了程序中的1处内存泄漏,并且报告如下:
有图有真相。可见VLD查找内存泄漏的能力十分强大,给出的内存泄漏报告信息量很大,也很精准.
现在我们给VLD增加一点点任务难度,我们把造成内存泄漏的代码封装一下,看看VLD是否还能精准地定位造成内存泄漏的语句位置。如代码 3-5 所示.
#include <stdio.h>
#include <stdlib.h>
#if defined(_WIN32) && defined(_DEBUG)
#include <vld.h>
#endif
static void do_something();
int main(int argc, char* argv[])
{
do_something();
printf("Hello from console application.\n");
return EXIT_SUCCESS;
}
static void do_something()
{
int x = 0;
char* p = NULL;
x++;
p = malloc(1);
x--;
}
代码 3-5:把造成内存泄漏的语句稍微封装一下 。
运行结果如图 3-8 所示。 图 3-8:运行结果4:精准定位出内存泄漏发生的代码位置 。
在代码 3-5 中,我们把造成内存泄漏的代码封装在了do_something()函数的第24行。在图 3 8中我们可以看到,VLD定位出了内存泄漏发生的代码位置是do_something()函数的第24行。VLD 工作得很好。虽然这里我只是给出了一个非常简单的例子,但是在实际工作中,我们的程序经常会很复杂,而 VLD 始终工作得很好,从未令我失望.
然后,如代码 3-6 所示,我们修复这一处内存泄漏,看看运行结果如何.
#include <stdio.h>
#include <stdlib.h>
#if defined(_WIN32) && defined(_DEBUG)
#include <vld.h>
#endif
static void do_something();
int main(int argc, char* argv[])
{
do_something();
printf("Hello from console application.\n");
return EXIT_SUCCESS;
}
static void do_something()
{
int x = 0;
char* p = NULL;
x++;
p = malloc(1);
x--;
free(p);
p = NULL;
}
代码 3-6:修复内存泄漏 。
我们编译出它的x64|Debug版本并运行,运行结果如图 3-9 所示。 图 3-9:运行结果5:内存泄漏的问题被修复 。
结果符合预期,从VLD的报告中我们得到的信息是:
但是这也不绝对,如果使用不当,Java/C#程序也会产生内存泄漏。 ↩︎ 。
请查阅维基百科上的“Memory Leak(内存泄漏)”词条,链接是:https://en.wikipedia.org/wiki/Memory_leak ↩︎ 。
VLD v2.5.1 发布于2017年10月17日,截止到发布本文的今天(2024年6月20日),https://kinddragon.github.io/vld/ 网页上仍然没有版本更新。 ↩︎ 。
VLD 依赖于dbghelp.dll,只要能支持dbghelp.dll,就能支持VLD。 ↩︎ 。
32位VLD的动态链接库的文件名是vld_x86.dll,64位VLD的动态链接库的文件名是vld_x64.dll。 ↩︎ 。
PDB(Program Data Base)文件,即程序的基本数据文件,是由Visual Studio对程序进行编译链接时产生的。该文件主要存储VS调试程序所需的基本信息,主要包括源文件名、变量名、函数名、FPO(帧指针)、对应的行号等调试信息。一般情况下PDB文件是在Debug模式下才会生成,但有些编译参数情况下Release模式也会产生PDB文件。 ↩︎ 。
MSVC的Debug Help Library动态链接库,详见:https://learn.microsoft.com/en-us/windows/win32/debug/debug-help-library ↩︎ 。
实际上在Release模式下,即使调用VLD,也不会产生任何影响。 ↩︎ 。
最后此篇关于在VisualStudio2022(VisualC++17)中使用VisualLeakDetector的文章就讲到这里了,如果你想了解更多关于在VisualStudio2022(VisualC++17)中使用VisualLeakDetector的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我注意到今天我们在 VS 2015 中的一个解决方案发生了变化。似乎为解决方案生成的测试项目使用与同一解决方案中现有测试项目不同的命名空间。 仅引用的测试项目 Microsoft.VisualStud
更新测试项目 NuGet 后出现此错误: The type 'TestClassAttribute' exists in both 'Microsoft.VisualStudio.QualityToo
我正在尝试设置 tfs 和 sharepoint 之间的构建集成。 我们有一个单独的构建服务器。我们已关注 these steps并检查它们的正确性 3 次。但是在 sharepoint 构建中,我们
今天在安装VS2019的时候,在安装的过程中一直无法进入安装界面,在网上找了各种方法试了将近40分钟都没有找到有效的办法,不过就快放弃的时候,问题解决了,哈哈哈!!!! 1.下载地址:https:
在 Visual Studio 中,用于在 WinForms 项目中添加元素的上下文菜单命令与 WPF 项目中显示的命令不同。事实上,我可以在第一个中看到“Add->Windows Form”,在第二
我正在创建一个多项目模板 问题是当我运行模板时,每个项目都会创建一个与项目名称匹配的目录文件夹。 我不希望每个项目都默认创建文件夹,如下所示: solutionfolder\Libraries\BL\
我下载了这门课http://www.codeproject.com/file/VersionInfo.asp 我用它从我当前运行的几个程序中获取文件信息。 当我想从我编写的程序中获取信息时,它工作正常
我正在尝试调试一个树状结构,所以我在每一层都制作了一个 watch 。我走得越低, watch 变量名称变得太长了。有没有办法重命名它们: {,,HTM_Projekt.exe}*(Node*){*}
我已经编写了一个 DLL,然后在我的解决方案中添加了对它的引用,但是当我在 usings 部分中声明它时,它给我的错误是无法识别,您是否缺少引用? 这是我设置解决方案的方式... 1-首先我创建了我的
我们有一个大型 C# 程序,分为 2 个主要组:内核 库和(客户)特定 应用程序和服务。 我们的 TFS 结构(简化)是这样的: 内核 深度学习计划 第 1 版 第 2 版 第 3 版 ... 客户A
VS 2010 Pro:我已经为我的库生成了一个类图,现在向它添加了一些类,但是类图只显示了旧类并且不会自动更新。所以我想知道这是不是这样,我应该每次都删除并重新添加类图吗?或者这些是我应该在 VS
关闭。这个问题需要更多focused .它目前不接受答案。 想改进这个问题吗? 更新问题,使其只关注一个问题 editing this post . 关闭 3 年前。 Improve this qu
我刚刚在 c# .net 中制作了一个程序,现在当我尝试保存或调试它时,我在消息框中收到此错误。这是我目前为我的项目编写的代码。错误代码“内存不足,无法继续执行程序”请帮忙。
关闭。这个问题是off-topic .它目前不接受答案。 想改善这个问题吗? Update the question所以它是 on-topic对于堆栈溢出。 8年前关闭。 Improve this q
我想扩展 Visual Studio,这样当有人右键单击解决方案资源管理器时,上下文菜单应该有一个新菜单项,比如“打开自定义表单”,单击哪个应该打开一个表单(这个表单实际上会接受一些设置并修改配置相应
IDE在启动时在启动屏幕上崩溃。我查看了日志,发现了很多错误: 14 2017/07/09 07:28:50.672 Information VisualSt
有没有人想知道 VisualStudio 将区域状态存储在源代码中的什么位置(展开或折叠?)。据我所知,它们没有存储在解决方案、项目或源文件中...... 最佳答案 所有这些类型的设置(区域折叠状态、
我正在使用T4(文本模板转换工具包)进行一些工作,并试图达到可以创建自己的自定义文本模板宿主的地步。但是,所有这些都依赖于 Microsoft.VisualStudio.TextTemplating
我创建了一个名为“WordpressAutomation”的新解决方案 我在这个解决方案中创建了一个名为“WordpressAutomation”的新项目,一个类库 我在这个解决方案中创建了一个新项目
最近我试用了 Visual Studio 2017。我们有一个 MSDN 订阅。我们正在开发一些我们正在编写为 WPF 应用程序的内部应用程序。这些应用程序需要安装在用户没有管理权限的用户计算机(Wi
我是一名优秀的程序员,十分优秀!