内存泄漏介绍
1.内存泄露, 也就是memory leak, 其意思是当程序做了申请内存这个操作之后, 之后对已申请的内存空间没办法去进行释放, 一次出现内存泄露的危害是能够被忽略的, 可要是内存泄露不断堆积起来, 那后果是非常严重的, 不管内存是什么样的数量, 迟早有一天都会被占光用尽没有剩余, 最终出现的结果便是导致OOM。
2.对系统而言, 内存泄漏是这般情况, 即你向其申请分配内存以供操作(new), 然而使用完毕后却未归还清理(delete), 如此一来, 你所申请到的那块内存, 你自身无法再度访问(或许你已弄丢它的地址), 并且系统也不能够再次将其分配给有需求的程序。
3.程序的内存空间
(1)在执行函数之际, 函数之内局部变量的存放单元皆能够于栈上予以创建, 当函数执行完毕之时, 这些存放单元会自动被释放。栈区的内存是依序连续分配的, 此依据仅是以这种方式出现的, 当我们声明变量时, 编译器会自动紧挨着当前栈区的末尾来实施内存分配, 比如说那个int a = 10。函数压入栈内的顺序是这样的: 返回的地址, 然后是从右至左的函数参数, 最后是成员变量。
(2)堆区, 其从堆上开辟内存, 这也被称作动态内存分配。程序于运行当中呢, 会借助malloc或者new去申请任意数量的内存。而程序员自身要负责在合适的时候, 运用free或者delete来释放内存。动态内存的生存期是由程序员自行决定的, 其使用相当灵活。然而要是在堆上分配了空间, 那就有责任去回收它。不然运行的程序将会出现内存泄漏。频繁地进行不同大小堆空间的分配以及释放, 将会产生堆内碎块。内存泄露所指的正是这一部分的泄露。
(3)静态全局分区中表现为, 全局变量以及静态变量的存储被安置于一处,其中初始状态的全局变量与静态变量共处于一块区域, 而未经历初始化的全局变量以及未初始化的静态变量则处于相邻的另外一方区域。
(4)这个区域被称作常量区, 常量以及字符串会被放置于此, 在程序结束以后, 会由系统来进行释放。
(5)代码区:存放函数体的二进制代码
int a = 0; //全局初始化区
char *p1; //全局未初始化区
void main()
{
int b; //栈
char s[] = “abc“;//栈
char *p2; //栈
char *p3 = “123456“; //123456\0在常量区,p3在栈上;体会与 char s[]="abc"; 的不同
static int c =0; //全局初始化区
p2 = (char *)malloc(20); //堆区
strcpy(p1, “123456“); //123456\0在常量区,编译器可能将它与p3指向的 “123456 “优化成一块
}
4.内存泄露主要是原因导致主要是new与delete未搭配使用, 存在主要是申请的对象指针未释放的状况。解决办法是运用智能指针, 途径是以智能指针采用应对处置。
相关于这个方面, 存在一篇文章讲述得相对更为明晰:C++内存管理里头的内存泄漏问题致使缘由以及化解办法。
内存检查工具一:valgrind
Valgrind是一款软件开发工具, 这个工具用于内存调试, 用于内存泄漏检测, 还用于性能分析, 它总体主要涵盖了七个代码测试的子工具:
1.Memcheck (常用)
使用来检测程序里出现的诸如内存泄露等内存问题的最常用工具, 在其作用下, 一切对malloc()/free()/new/delete的调用都能够被捕获。
2.Callgrind (常用)
Callgrind收集程序运行之际的一些数据, 构建函数调用关系图这件事, 还能够有所抉择地开展cache模拟。它能够获取粒度为函数、代码行以及指令各级别的性能数据, 确切来讲, 我们能够获取某个函数、某行代码、某条指令之处累计付诸执行的指令条数, 并且能够针对分析好的数据予以可视化, 情况如下所示:。
参考博客为: Linux C/C++ 调试之三, 性能分析工具 callgrind 的使用, 具体使用方法可据此。
3.Cachegrind
有这么一种Cache分析器, 它主要模拟CPU里的那一级缓存I1、Dl以及二级缓存, 并且, 它能够精准无误地指出程序当中cache的丢失情况以及命中情况。要是有需要的话, 它还能够给我们提供像cache丢失的次数、内存引用的次数, 以及每行代码、每个函数、每个模块、整个程序所产生的指令数这些数据。这些对优化程序能够起到极大的帮助。
4.Helgrind (常用)
它主要是被用于检查多线程程序里出现的竞争问题, Helgrind找寻内存当中被多个线程去访问的区域, 并且这些区域是没有一贯加锁的, 而这些区域通常是线程之间失去同步的所在之处, 且会致使难以发掘出来的错误, Helgrind实现了一种名为“Eraser”的竞争检测算法, 还做了进一步的改进, 以此减少了报告错误的次数, 不过呢, Helgrind依旧处于实验阶段。
5.Massif
被称为堆栈模拟器的那个东西, 它具备一种能力, 这种能力可以用来测定程序于堆栈这个特定区域里究竟使用了多少内存, 并且还能够把堆块的大小, 还有堆管理块以及栈的大小告知给我们。马西夫这个名字听起来有些奇怪, 它展现出来的作用是帮助我们降低内存的使用量, 在那些配备了虚拟内存的当代类型系统里面, 它具备这样一种效能, 就是能够加快我们程序的运行速度, 同时还能降低处于交换环境这一区域中间的程序的停留几率。除此之外, 莱克伊和努格伦德这两个东西同样会提了供。我们先来看看莱克伊, 它是一种小型的工具, 在实际应用的过程当中它被应用到操作的场景是非常少的;再说说努格伦德, 作为一个工具它只为开发者们呈现如何去建立这样一个工具的相关信息。
使用方法:
1.安装
(1)直接安装:
sudo apt-get install valgrind
(2)或者源码安装:
wget https://sourceware.org/pub/valgrind/valgrind-3.15.0.tar.bz2
tar -xjvf valgrind-3.15.0.tar.bz2
cd valgrind-3.15.0/
valgrind因支持多个平台, 依据当前主机配置来进行valgrind设定。
./configure
make
sudo make install
查看一下版本看看是否安装好
valgrind --version
2.使用

(1)为了定位代码位置,需要在gcc编译时添加-g选项
gcc -Wall malloc1.c -g -o malloc1
对应与CmakeList.txt中,应添加选项:
add_definitions("-Wall -g")
(2)常用的指令:
查看设置项: valgrind --help
进行内存泄露检查时, 使用valgrind工具, 其工具类型为memcheck, 进行完整泄露检查, 针对的程序是./oxfordmm。
当中valgrind打印的日志多到在终端里看都看不完, 因而需要做成日志文件输出, 在那文件中查看会比较便利, 其指令为: valgrind --tool=memcheck --log-file=mem.log --leakCheck=full ./oxfordmm。
输出的日志文件如下图所示:
一定要重点关注definitely lost项, 与之相对应的错误信息, 能够在官网上去查看哟:
(4)对方法进行总结, 这个工具具备比较强大的功能, 使用起来也相对便利, 然而运行的时候速度太过缓慢。它将原来程序的速度拖慢至10倍以上, 不适用于大规模的程序检测。并且其输出的信息较为冗余, 要找到有用的信息颇为麻烦, 所以推荐下一个工具, 即谷歌推出的AddressSanitizer。
内存检查工具二:AddressSanitizer(推荐)
谷歌旗下的开源工具地址清理器(AScan)可助力咱们检测内存泄漏、缓冲区溢出、越界访问这类内存错误, 它速度极快, 仅使程序变慢大概两倍。自gcc 4.8起, 地址清理器成为gcc的一部分, 无需额外安装就能直接运用标点符号!
使用方法:
(1)在CmakeList.txt中添加特定的编译选项:
将以特定方式编译你的程序, 这种编译要采用 -fsanitize=address 选项, 之后还要在此基础上进行链接。
通过使用 -fno-omit-frame-pointer 进行编译, 其目的旨在能够于错误消息里增添更好的堆栈跟踪。
add_definitions("-Wall -g")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-omit-frame-pointer -fsanitize=leak")
如果需要也检查其他内存错误,也可以添加如下设置项:
add_definitions("-Wall -g")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
(2)直接运行程序就好:
./oxfordmm
实验结果如下图所示:
某些时候, 当运行之上所提及的编译选项, 在启用分析工具之际会产生错误进而直接退出, 然而在不启用该工具之时就不会出现此种状况。所幸的是, 工具能够指出出错的位置, 从图里能够看到位置处于。
UpdateBoundaryVoxel(ORB_SLAM2::KeyFrame*, int) /home/shiqi/cubeslam_orb_dot _oxfordmm/src/cube_slam/orb_object_slam/src/MapObject.cc:3706
中,直接改掉该行就好,然后运行效果如下图所示:
这个工具所呈现的错误信息, 具有比较简约的特点, 其中实用的内容较多, 并且在应用方面更加便捷, 果真是首选的工具!
参考博客:
1.内存泄漏检测神器valgrind
2.AddressSanitizer使用介绍
3.C++ 内存管理中内存泄漏问题产生原因以及解决方法