我正在参加「掘金·启航计划」
👀持续更新中……
[toc]
前言
本文为项目中服务程序的内存泄漏,挑了其中一部分比较常见的内存泄漏进行分析和修改。
关于内存泄漏和分析的文章可查看博客相关文章,有 UMDH 和 vld 两种方式,可根据个人需求展开分析。
泄漏分类
# malloc 内存泄漏
下述日志为一次 malloc 未正确释放导致的内存泄漏。这种问题比较常见,不用多说。
ntdll.dll!RtlAllocateHeap()
***\heap\malloc_base.cpp (34): XXX.dll!_malloc_base() + 0xF bytes
XXX.dll!_event_debugx() + 0x1A7 bytes
解决方案:
根据提示的位置找到并释放该内存。
char *ch = (char*)malloc(sizeof(8));
free ch;
ch = NULL;
另外,也可以使用智能指针管理该指针:
char *ch = (char*)malloc(sizeof(8));
shared_ptr<char> spCh(ch);
# new 内存泄漏
关于 new 的内存泄漏分析写了一段代码用来展示一下:
注:代码 Section2 部分为一个崩溃代码,堆内存申请后使用时一处,而在堆内存申请和释放时以及程序结束时释放堆内存时,都 存在堆溢出检查 ,检查点会抛出异常,导致程序奔溃。
// 代码 Section2
// 该函数代码还涉及奔溃问题
int* test_heap_alloc()
{
int* pTable = new int(256); // 申请一个int结构体变量,初始值为256;
for (int i = 0; i < 256; i++)
pTable[i] = i;
return pTable;
}
int main ()
{
test_heap_alloc();
// 执行上述代码之后再去下边这句申请堆内存会奔溃。
char* p = new char(0); // 申请一个字节,内容初始化为0
return 0;
}
以下为 vld 生成的泄漏日志:
WARNING: Visual Leak Detector detected memory leaks!
---------- Block 1 at 0x010AAC68: 4 bytes ----------
Leak Hash: 0x03729B3D, Count: 1, Total 4 bytes
Call Stack (TID 33760):
ucrtbase.dll!malloc()
d:\agent\_work\3\s\src\vctools\crt\vcstartup\src\heap\new_scalar.cpp (35): vldforptr.exe!operator new() + 0x8 bytes
d:\code_source\c++\vs2019\vldforptr\vldforptr.cpp (45): vldforptr.exe!main() + 0x7 bytes
KERNEL32.DLL!BaseThreadInitThunk() + 0x19 bytes
ntdll.dll!RtlGetAppContainerNamedObjectPath() + 0x11E bytes
ntdll.dll!RtlGetAppContainerNamedObjectPath() + 0xEE bytes
Data:
00 00 00 00 ........ ........
解决方案:
调用 delete 释放 new 出来的内存。
-
问题:不确定变量什么时候使用完的,如何释放?
// 使用智能指针 char *ch = new char[256]; std::shared_ptr<char> spCh(ch);
# strdup 内存泄漏
strdup函数说明:
功能:将字符串拷贝到新建的位置处
返回值 :返回一个指向新字符串的指针,该字符串是字符串s的副本,如果分配空间失败,则返回NULL值。新字符串的内存由strdup函数原型内部的malloc()获得,需用free()释放。
ntdll.dll!RtlAllocateHeap()
minkernel\crts\ucrt\src\appcrt\heap\malloc_base.cpp (34): XXX.dll!_malloc_base() + 0xF bytes
XXX.dll!BUF_strndup() + 0x8A bytes
把返回内存地址的释放权交给了别的变量,这就很容易忘记释放,所以 strdup 这个函数也很容易造成内存泄漏。
整理
# _malloc_base
_malloc_base 就是编译器编译之后的 malloc。
查看vld的log可以看到,堆栈显示的 _malloc_base 所在的文件夹为 minkernel\crts\ucrt\src\appcrt\heap\malloc_base.cpp,这个文件就是 malloc 声明和定义的文件。