[toc]

前言

本文为项目中服务程序的内存泄漏,挑了其中一部分比较常见的内存泄漏进行分析和修改。

关于内存泄漏和分析的文章可查看博客相关文章,有 UMDHvld 两种方式,可根据个人需求展开分析。

泄漏分类

# malloc 内存泄漏

下述日志为一次 malloc 未正确释放导致的内存泄漏。这种问题比较常见,不用多说。

1
2
3
ntdll.dll!RtlAllocateHeap()
***\heap\malloc_base.cpp (34): XXX.dll!_malloc_base() + 0xF bytes
XXX.dll!_event_debugx() + 0x1A7 bytes

解决方案:

根据提示的位置找到并释放该内存。

1
2
3
char *ch = (char*)malloc(sizeof(8));
free ch;
ch = NULL;

另外,也可以使用智能指针管理该指针:

1
2
char *ch = (char*)malloc(sizeof(8));
shared_ptr<char> spCh(ch);

# new 内存泄漏

关于 new 的内存泄漏分析写了一段代码用来展示一下:

注:代码 Section2 部分为一个崩溃代码,堆内存申请后使用时一处,而在堆内存申请和释放时以及程序结束时释放堆内存时,都 存在堆溢出检查 ,检查点会抛出异常,导致程序奔溃。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 代码 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 生成的泄漏日志:

1
2
3
4
5
6
7
8
9
10
11
12
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 出来的内存。

  1. 问题:不确定变量什么时候使用完的,如何释放?

    1
    2
    3
    // 使用智能指针
    char *ch = new char[256];
    std::shared_ptr<char> spCh(ch);

# strdup 内存泄漏

strdup函数说明:

功能:将字符串拷贝到新建的位置处

返回值 :返回一个指向新字符串的指针,该字符串是字符串s的副本,如果分配空间失败,则返回NULL值。新字符串的内存由strdup函数原型内部的malloc()获得,需用free()释放。

1
2
3
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 声明和定义的文件。

1
2
3
4
5
6
7
领导您好!
以下内容为本次绩效期间我的工作概述以及自我评价。

本次绩效期间,我的主要工作内容集中在零信任国信版本和天擎零信任插件部分,同时也负责了部分工行、标板的需求开发(SPA、异常告警、命令行登录等)。零信任国信版本共计发布版本两次,均在发布版本之前完成了需求的开发和bug的修复,涉及的需求十多项,需求提测均通过,在完成需求的同时,整理编写了相应的技术开发文档十多篇,同时也补充了零信任客户端部分配置文件的说明文档。开发同时,针对国信零信任版本的升级故障问题(升级失败,升级检测问题),优化了该部分的逻辑,对整个客户端的无逻辑代码和日志部分进行了优化,以便于后续快速定位和分析问题,国信发布版本期间,为保证出包顺利,解决临时出现的问题,与团队一起解决问题并完成版本发布的任务;零信任插件部分,插件的开发让我学习到了较多框架方面的知识,了解了插件的开发以及团队联调的过程,零信任插件的开发在团队帮助下开发较为顺利,并且按时提测,且完成度较高,故障部分相对较少,调整部分基本为业务方面的逻辑调整。工行和标板的需求也是在计划内完成了需求的开发并提测成功,本次绩效期间,工作充实,如期完成了各项需求开发。不足就是多个需求的开发和提测过程相对较慢,由于环境(tac)问题,在开发自测和提测过程中出现了效果不一致的情况,在以后开发中需要注意该方面问题对开发提测的影响,提测前尽量保证自测完整,需求完善。

以上就是本期自我评价。