当前位置: 首页 > news >正文

C++内存泄露排查

  内存泄漏是指程序动态分配的内存未能及时释放,导致系统内存逐渐耗尽,最终可能造成程序崩溃或性能下降。在C++中,内存泄漏通常发生在使用new或malloc等分配内存的操作时,但没有正确地使用delete或free来释放这块内存。

  在日常开发过程中,为了避免内存泄露,一般都用智能指针去自动管理内存,避免忘记释放。

1.内存泄露动态分析工具——Valgrind

Valgrind是运行在linux上的程序分析工具,它包含很多小工具: memcheck(内存泄露检查工具)等

1.1 安装Valgrind

下载链接:https://valgrind.org/downloads/current.html#current

1.2 Valgrind简单上手和分析

参考:Linux 性能分析valgrind(一)之memcheck使用

命令(以下程序均可以使用此命令):

valgrind --log-file=valgrind.log --tool=memcheck --leak-check=full --show-leak-kinds=all ./your_program
# --log-file: 报告文件名。如果没有指定,输出到stderr
# --tool=memcheck: 指定Valgrind使用的工具,Valgrind是一个工具集,包括Memcheck、Cachegrind、Callgrind等多个工具,memcheck是缺省项。
# --leak-check: 指定如何报告内存泄漏(memcheck能检查多种内存使用错误,内存泄漏是其中常见的一种),可选值有:
#  	- no 不报告
#  	- summary 显示简要信息,有多少个内存泄漏。summary是缺省值。
#  	- yes 和 full 显示每个泄漏的内存在哪里分配。
# --show-leak-kinds: 指定显示内存泄漏的类型的组合。类型包括definite, indirect, possible,reachable。也可以指定all或none。[缺省值](https://www.zhihu.com/search?q=缺省值&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra={"sourceType"%3A"article"%2C"sourceId"%3A92074597})是definite,possible。 运行一段时间后想停止进程不要kill掉,需要ctrl + c来结束,输出的log会在上述命令中的valgrind.log中。

程序1(C程序):使用未初始化的内存

#include <stdio.h>
#include <stdlib.h> int main(void)
{char *p; char c = *p; printf("\n [%c]\n",c); return 0;
}

Valgrind重点结果信息:使用未初始化的变量,无效的读( 读取没有分配地址空间的区域数据 )

==73374== Use of uninitialised value of size 8
==73374==    at 0x400513: main (in /home/bossdog/3Growup/valgrind/test1/a.exe)
==73374== 
==73374== Invalid read of size 1
==73374==    at 0x400513: main (in /home/bossdog/3Growup/valgrind/test1/a.exe)
==73374==  Address 0x0 is not stack'd, malloc'd or (recently) free'd

程序2(C程序):在内存被释放后进行读/写

#include <stdio.h>
#include <stdlib.h> int main(void)
{char *p = malloc(1);*p = 'a'; char c = *p; printf("\n [%c]\n",c); free(p);c = *p;return 0;
}

Valgrind重点结果信息:

==74181== Invalid read of size 1
==74181==    at 0x4005E3: main (in /home/bossdog/3Growup/valgrind/test1/a.exe)
==74181==  Address 0x520a040 is 0 bytes inside a block of size 1 free'd
==74181==    at 0x4C3195F: free (vg_replace_malloc.c:872)
==74181==    by 0x4005DE: main (in /home/bossdog/3Growup/valgrind/test1/a.exe)
==74181==  Block was alloc'd at
==74181==    at 0x4C2F075: malloc (vg_replace_malloc.c:381)
==74181==    by 0x4005A8: main (in /home/bossdog/3Growup/valgrind/test1/a.exe)

程序3(C程序): 内存泄露

#include <stdio.h>
#include <stdlib.h> int main(void)
{char *p = malloc(1);*p = 'a'; char c = *p; printf("\n [%c]\n",c); return 0;
}

Valgrind重点结果信息:直接泄露

==74814== 1 bytes in 1 blocks are definitely lost in loss record 1 of 1
==74814==    at 0x4C2F075: malloc (vg_replace_malloc.c:381)
==74814==    by 0x400558: main (in /home/bossdog/3Growup/valgrind/test1/a.exe)

程序4(C++程序):不匹配使用malloc free 和 new delete

#include <stdio.h>
#include <stdlib.h>
#include<iostream> int main(void)
{char *p = (char*)malloc(1);*p = 'a'; char c = *p; printf("\n [%c]\n",c);delete p;return 0;
}

Valgrind重点结果信息:

==75341==    by 0x400683: main (in /home/bossdog/3Growup/valgrind/test1/a.exe)
==75341==  Address 0x5b20c80 is 0 bytes inside a block of size 1 alloc'd
==75341==    at 0x4C2F075: malloc (vg_replace_malloc.c:381)
==75341==    by 0x400648: main (in /home/bossdog/3Growup/valgrind/test1/a.exe)

程序5(C程序): 两次释放内存

#include <stdio.h>
#include <stdlib.h> int main(void)
{char *p = (char*)malloc(1);*p = 'a'; char c = *p;printf("\n [%c]\n",c);free(p);free(p);return 0;
}

Valgrind重点结果信息:

==76126== Invalid free() / delete / delete[] / realloc()
==76126==    at 0x4C3195F: free (vg_replace_malloc.c:872)
==76126==    by 0x4005EA: main (in /home/bossdog/3Growup/valgrind/test1/a.exe)
==76126==  Address 0x520a040 is 0 bytes inside a block of size 1 free'd
==76126==    at 0x4C3195F: free (vg_replace_malloc.c:872)
==76126==    by 0x4005DE: main (in /home/bossdog/3Growup/valgrind/test1/a.exe)
==76126==  Block was alloc'd at
==76126==    at 0x4C2F075: malloc (vg_replace_malloc.c:381)
==76126==    by 0x4005A8: main (in /home/bossdog/3Growup/valgrind/test1/a.exe)

1.3 官方手册

官方手册

2.实际问题分析

struct image_u8
{const int32_t width;const int32_t height;const int32_t stride;uint8_t *buf;
};std::shared_ptr<image_u8> image;image.reset(new image_u8({ frame_out.stFrameInfo.nWidth,frame_out.stFrameInfo.nHeight,frame_out.stFrameInfo.nWidth,new uint8_t[frame_out.stFrameInfo.nWidth * frame_out.stFrameInfo.nHeight * sizeof(uint8_t)] }));image.reset();

std::shared_ptr 会自动管理 image_u8对象的生命周期,但是它不会管理 buf(即 uint8_t*
类型的指针)所指向的内存。
当执行image.reset();之后,image指针被释放重置了,但是指针所指向的指针即 uint8_t*没有被释放,造成了内存泄露。

记录

  • 二级指针被释放时,不会自动释放一级指针中所指向的内存。
    在这里插入图片描述

参考:https://blog.csdn.net/weixin_44477424/article/details/136417250

http://www.lryc.cn/news/521060.html

相关文章:

  • Http 响应状态码 前后端联调
  • 48_Lua错误处理
  • shell脚本回顾1
  • 【3】管理无线控制器
  • SOME/IP 协议详解——服务发现
  • Flutter:封装ActionSheet 操作菜单
  • 力扣 全排列
  • Golang 设计模式
  • Matlab 具有周期性分布的死角孔的饱和空气多孔材料的声学特性
  • maven 项目怎么指定打包后名字
  • Java Web开发进阶——Spring Boot与Thymeleaf模板引擎
  • 论文笔记(四十七)Diffusion policy: Visuomotor policy learning via action diffusion(下)
  • 开始使用Panuon开源界面库环境配置并手写VS2019高仿界面
  • 新垂直电商的社交传播策略与AI智能名片2+1链动模式S2B2C商城小程序的应用探索
  • WPS计算机二级•表格函数计算
  • ESP32S3官方例程如何使用
  • 新版 MacOS 无法从 /usr/local/lib 加载动态链接库的解决办法
  • 【Varnish】:解决 Varnish 7.6 CDN 静态资源缓存失效问题
  • 【记录】篡改猴插件下载网页m3u8视频
  • PID控制器 (Proportional-Integral-Derivative Controller) 算法详解及案例分析
  • 【Java设计模式-5】装饰模式:给咖啡加点“佐料”
  • C++ using(八股总结)
  • 《分布式光纤传感:架设于桥梁监测领域的 “智慧光网” 》
  • C++(5)
  • 【进程与线程】程序和进程在内存中的表现
  • 个人主页搭建全流程(Nginx部署+SSL配置+DCDN加速)
  • 语音合成的预训练模型
  • 前端组件开发:组件开发 / 定义配置 / 配置驱动开发 / 爬虫配置 / 组件V2.0 / form表单 / table表单
  • Swagger生成Api文档的增强解决方案--knife4j
  • Node.js - HTTP