用mtrace定位内存泄漏

一. 缘起

有的公众号读者,看完我上次写给大学生的查bug方法后,希望我多分享一些查bug的实践经验和具体步骤,比如如何查内存泄漏和core dump问题。所以,就打算写这篇文章。

二. 内存泄漏简介

内存泄漏,是一个谈虎色变的问题。我个人的基础非常差,大学毕业后,才第一次听说内存泄漏。当时,我有点懵圈,心想内存泄漏了,是要重新去买新的内存设备吗?很傻很天真!

后来,我又听说了很多次内存泄漏,查资料后才知道,原来这是一个软件层面的东西。比如,使用了malloc, 但没有使用free, 或者使用了new, 但没有使用delete, 都会造成内存泄漏。

为什么说内存泄漏会谈虎色变呢?因为:

  • 内存泄漏危害性大

  • 内存泄漏潜伏时间长

  • 内存泄漏不容易定位

那么,如果内存泄漏了,我们该如何去定位呢?在C/C++相关的面试中,不问这个问题的面试官,是不合格的;不会回答这个问题的面试者,也是不合格的。当然,这种说法,似乎有一点绝对。

有的面试者回答,只有小心配对使用malloc/free和new/delete, 就能避免内存泄漏。显然,这种面试者缺乏基本的工程实践认知,缺乏对敌人的敬畏。

有的面试者回答,使用智能指针,就能避免内存泄漏。显然,这只是一种预防机制。在实际项目中,各种复杂因素导致的后果是内存已经泄漏,需要定位。

还有的面试者,更是想出了出人意料的答案,那就是检查代码!这又是对敌人缺乏了解啊。大型工程的代码动辄几十万行,谁敢走读代码来查内存泄漏呢?

对我而言,查杀bug是我的相对强项(实话说,架构能力需要加强)。mtrace和valgrind是典型的内存泄漏分析工具。今天,我们聊mtrace定位内存泄漏。

三. mtrace简介

我们来看下mtrace的用途:

ubuntu@VM-0-15-ubuntu:~$ man mtrace
MTRACE(1)                                       Linux user manual                                       MTRACE(1)NAMEmtrace - interpret the malloc trace logSYNOPSISmtrace [option]... [binary] mtracedataDESCRIPTIONmtrace  is a Perl script used to interpret and provide human readable output of the trace log contained inthe file mtracedata, whose contents were produced by mtrace(3).  If binary  is  provided,  the  output  ofmtrace  also  contains  the  source file name with line number information for problem locations (assumingthat binary was compiled with debugging information).For more information about the mtrace(3) function and mtrace script usage, see mtrace(3).

显然,mtrace命令是用来分析malloc函数的trace log. 

那么,这个trace log是怎么生成的呢? 且看上面的see mtrace(3). 有的朋友看到这里,不知道怎么敲命令了,以为是:

ubuntu@VM-0-15-ubuntu:~$ man mtrace(3)
-bash: syntax error near unexpected token `('
ubuntu@VM-0-15-ubuntu:~$

其实,正确的姿势如下:

ubuntu@VM-0-15-ubuntu:~$ man 3 mtrace
MTRACE(3)                                   Linux Programmer's Manual                                   MTRACE(3)NAMEmtrace, muntrace - malloc tracingSYNOPSIS#include <mcheck.h>void mtrace(void);void muntrace(void);DESCRIPTIONThe  mtrace()  function installs hook functions for the memory-allocation functions (malloc(3), realloc(3)memalign(3), free(3)).  These hook functions record tracing information about memory allocation and  deal[mlocation.   The tracing information can be used to discover memory leaks and attempts to free nonallocatedmemory in a program.The muntrace() function disables the hook functions installed by mtrace(), so that tracing information  isno  longer recorded for the memory-allocation functions.  If no hook functions were successfully installedby mtrace(), muntrace() does nothing.When mtrace() is called, it checks the value of the environment variable MALLOC_TRACE, which  should  con[mtain  the  pathname of a file in which the tracing information is to be recorded.  If the pathname is suc[mcessfully opened, it is truncated to zero length.If MALLOC_TRACE is not set, or the pathname it specifies is invalid or not writable, then  no  hook  func[mtions  are  installed, and mtrace() has no effect.  In set-user-ID and set-group-ID programs, MALLOC_TRACEis ignored, and mtrace() has no effect.

显然,mtrace函数是用来记录malloc的trace log的。

所以,对于mtrace, 我们有如下的基本认知:

  • mtrace函数记录malloc的trace log

  • mtrace命令分析上述记录的trace log

这也就是用mtrace来定位内存泄漏的原理。那么,具体如何来查内存泄漏呢?不要着急,继续往下看。

四. 用mtrace定位内存泄漏

首先,我们来写一段有内存泄漏的程序:

#include <stdio.h>int main()
{setenv("MALLOC_TRACE", "test.log", "1");mtrace();int *p = (int *)malloc(2 * sizeof(int));return 0;
}

我们来分析一下这段程序:

  • setenv是设置相关环境变量。

  • mtrace函数记录malloc的trace log.

  • malloc函数用于分配堆内存

我们来编译并运行一下(注意在编译时带-g参数):

ubuntu@VM-0-15-ubuntu:~$ gcc -g test.c
ubuntu@VM-0-15-ubuntu:~$ 
ubuntu@VM-0-15-ubuntu:~$ 
ubuntu@VM-0-15-ubuntu:~$ ./a.out
ubuntu@VM-0-15-ubuntu:~$ ls test.log 
test.log
ubuntu@VM-0-15-ubuntu:~$ cat test.log 
= Start
@ ./a.out:[0x4005eb] + 0x1649570 0x8
@ /lib/x86_64-linux-gnu/libc.so.6:(clearenv+0x5d)[0x7f1bc48f7e9d] - 0x1649010
@ /lib/x86_64-linux-gnu/libc.so.6:(tdestroy+0x4cf)[0x7f1bc49c291f] - 0x16490e0
@ /lib/x86_64-linux-gnu/libc.so.6:[0x7f1bc4a3223c] - 0x1649100

显然,编译运行后,生成了trace log, 即test.log文件。用cat命令查看,貌似也发现不了什么东西,这是因为,姿势错了。

我们不仅仅要用test.log, 还要结合二进制文件a.out呢,如下:

ubuntu@VM-0-15-ubuntu:~$ mtrace a.out test.log
- 0x00000000018ab010 Free 3 was never alloc'd 0x7fb41725fe9d
- 0x00000000018ab0e0 Free 4 was never alloc'd 0x7fb41732a91f
- 0x00000000018ab100 Free 5 was never alloc'd 0x7fb41739a23cMemory not freed:
-----------------Address     Size     Caller
0x00000000018ab570      0x8  at /home/ubuntu/test.c:8
ubuntu@VM-0-15-ubuntu:~$

Oh, nice啊!终于查出是第8行,存在内存泄漏。接下来,我们打算修复代码,并再次验证。

五. 修复后再验证

修复内存泄漏后,代码为:

#include <stdio.h>int main()
{setenv("MALLOC_TRACE", "test.log", "1");mtrace();int *p = (int *)malloc(2 * sizeof(int));free(p);return 0;
}

编译运行,并查看是否有内存泄漏:

ubuntu@VM-0-15-ubuntu:~$ gcc -g test.c
ubuntu@VM-0-15-ubuntu:~$ 
ubuntu@VM-0-15-ubuntu:~$ 
ubuntu@VM-0-15-ubuntu:~$ ./a.out
ubuntu@VM-0-15-ubuntu:~$ mtrace a.out test.log
- 0x00000000006ad010 Free 4 was never alloc'd 0x7faa9b044e9d
- 0x00000000006ad0e0 Free 5 was never alloc'd 0x7faa9b10f91f
- 0x00000000006ad100 Free 6 was never alloc'd 0x7faa9b17f23c
No memory leaks.
ubuntu@VM-0-15-ubuntu:~$

看到No memory leaks后,心情就好了,没有内存泄漏了。

六. 最后的话

无论是笔试面试,还是平时工作,对于内存泄漏问题,都要有自己的一套处理办法。


推荐阅读:

专辑|Linux文章汇总

专辑|程序人生

专辑|C语言

我的知识小密圈

关注公众号,后台回复「1024」获取学习资料网盘链接。

欢迎点赞,关注,转发,在看,您的每一次鼓励,我都将铭记于心~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/466431.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

为什么每个人都应该尝试Ubuntu下篇 Why Everyone Should Try Ubuntu 分享

但是老实说&#xff0c;我认为 Ubuntu 拥有长期的生存能力重要于其短期的实用主义。最近几年来&#xff0c;对于改进 Linux 桌面方面&#xff0c;Ubuntu 做得比其他发行版本要多。这就是我已详细讨论的&#xff0c;其带来的实际好处&#xff0c;但它也有许多不明确的地方。感谢…

陪我长大的村,镇,学校和家乡

我们村在广西河池市金城江区九圩镇江潭村山岳屯上面的字可以省略&#xff0c;因为看起来确实麻烦。地图上是这样显示的。小说我们村的那座桥&#xff0c;那座老桥据说是我爷爷那一辈人建起来的&#xff0c;用的是实打实的大石头。我上小学那段那会&#xff0c;我们同龄的小孩都…

Linux硬盘分区

MBR分区主分区&#xff1a;14&#xff0c;一块硬盘最多4个主分区&#xff0c;对主机必须有&#xff0c;主分区可以格式化ntfs&#xff0c;存数据。扩展分区&#xff1a;14&#xff0c;一块硬盘最多一个扩展分区&#xff0c;可以没有扩展分区&#xff0c;可以划分成更小的单元&a…

使用FileZilla Server轻松搭建个人FTP服务器

使用FileZilla Server轻松搭建个人FTP服务器 添加一个用户&#xff0c;然后在“共享文件夹”下设置将要设为FTP目录的文件夹和操作权限&#xff0c;点击确定 https://jingyan.baidu.com/article/ed15cb1bb6de421be3698188.html 可以为不同的用户创建不同的目录&#xff0c;新建…

TQ210——启动方式

TQ210——启动方式

AngularJS:应用

ylbtech-AngularJS&#xff1a;应用1.返回顶部 1、AngularJS 应用 现在是时候创建一个真正的 AngularJS 单页 Web 应用&#xff08;single page web application&#xff0c;SPA&#xff09;了。 AngularJS 应用实例 您已经学习了足够多关于 AngularJS 的知识&#xff0c;现在可…

你可能对电灯泡一无所知

今天在公众号“电路啊中看到一篇推文”超低成本的LED恒流驱动电路[1] &#xff0c;作者讲述了看到一个仅仅售价1元人民币的LED灯泡&#xff0c;并包邮时所感到的惊讶。为了消除惊讶&#xff0c;作者还花巨资&#xff08;1&#xff09;购买 薅羊毛 了该款灯泡并拆开一看究竟。▲…

TQ210——S5PV210启动过程

TQ210——S5PV210启动过程 1、S5PV210内存地址映射 S5PV210 含有一个大小为64KB的IROM&#xff0c;起始地址为0xD0000000&#xff0c;结束地址为0xD000FFFF&#xff1b;含有一个大小为96KB的 IRAM&#xff0c;起始地址为0xD0020000&#xff0c;结束地址为0xD0037FFF;内存起始地…

composer-安装插件包

上一步完成后&#xff0c;选定国内镜像地址&#xff0c;以为下载插件包做准备 https://pkg.phpcomposer.com/ 安装完componser后使用下面这条命令即可(设置国内镜像地址)&#xff1a; composer config -g repo.packagist composer https://packagist.phpcomposer.com 插件包地址…

555定时器是如何被发明的?

在电子领域中&#xff0c; 555 定时器集成芯片[1] 是著名集成芯片之一。然而很多人并不知道它是如何被发明的&#xff1f;下面是发表在网站 Circuit Today上的一篇文章[2] &#xff0c;带你重温从555被发明开始直到当今的发展历程。一、什么是555定时集成芯片&#xff1f;555芯…

TQ210——交叉编译器的安装

TQ210——交叉编译器的安装 1、 下载arm-linux-交叉工具链 2、 在ubuntu下新建一个目录&#xff0c;通过Samba拖到虚拟机ubuntu中 3、由于刚创建的目录没有samba权限&#xff0c;因此要加权限。 4、解压交叉工具连&#xff0c;-C指定目录 5、用arm-linux-gcc–v查看版本&#…

CCCC L1-002. 打印沙漏【图形打印】

L1-002. 打印沙漏 时间限制400 ms内存限制65536 kB代码长度限制8000 B判题程序Standard作者陈越本题要求你写个程序把给定的符号打印成沙漏的形状。例如给定17个“*”&#xff0c;要求按下列格式打印 ************ *****所谓“沙漏形状”&#xff0c;是指每行输出奇数个符号&am…

Samsung原版44B0X的Bootloader分析

原作者&#xff1a;BCbbs 1&#xff0e;中断向量表 AREA Init,CODE,READONLY 说明&#xff1a; 1.从代码看Init段就是要写入0x00地址的原始中断向量&#xff0c;因此把这个文件编译生成的44binit.O和Init填入ADS的Linker-Layout页对应项中(这样编译器会把该段代码编译到0X…

C语言,把指针按地上摩擦,爽

不要陷在指针里面&#xff0c;最好的方法是跳出指针&#xff0c;我们从最终结果来思考问题。于是我的解题思路总是很偏&#xff0c;但是直指本质。我们写一段代码&#xff1a;编译&#xff0c;反编译&#xff0c;反编译这里我们用objdump -d hello >1.txt&#xff0c;如果你…

嵌入生活的嵌入式,超市里的电子价签

纸质价签 VS 电子价签快过年了&#xff0c;今天特意走访了居住地附近的2家超市&#xff0c;不过不是为了买年货&#xff0c;而是为了给这篇文章提供一手的素材。今天我们来聊聊超市里的电子价签。我去的第一家超市&#xff0c;货架上的标签是这样的&#xff0c;这也是我们最常见…

张一鸣:大学四年收获及工作感悟

大学里的三点收获2001年我考入了南开大学&#xff0c;起初大学的生活是让人有点失落的&#xff0c;但慢慢地从安静朴素的校园和踏实努力的氛围中&#xff0c;我还是找到了自己的节奏。大学期间我主要在做三件事情 &#xff0c;一是写代码&#xff0c;因为我是搞技术的&#xff…

C语言实现x的n次方

C语言实现x的n次方#include <stdio.h> // codeblock编辑和编译的#define uint8_t unsigned char #define uint32_t unsigned int #define POWER 16// 求x的n次方&#xff0c;返回x的n次方的值 uint32_t Power(uint8_t x, uint8_t n) {uint8_t i;uint32_t val 1;for(i …

关于JTAG,你知道的和不知道的都在这里

01JTAG简介JTAG&#xff08;JointTest ActionGroup&#xff09;是一个接口&#xff0c;为了这个接口成立了一个小组叫JTAG小组&#xff0c;它成立于1985年。在1990年IEEE觉得一切妥当&#xff0c;于是发布了IEEE Standard 1149.1-1990&#xff0c;并命名为Standard Test Access…

Java:从99瓶子数到0,一个int、String变量、while循环、if条件测试

一、程序执行流程图&#xff1a; 二、代码实现&#xff1a; one: public static void main(String[] args) {int beerNumber99; String beerName"bottles";while (beerNumber<100){ System.out.println(beerNumber" :"beerName); System.out.println…

新唐单片机如何生成精确延迟

最近在搞新唐单片机&#xff0c;所以记录下这部分内容。之前的相关文章呵&#xff0c;你会51单片机的精确延时吗&#xff1f;假如使用者想要产生精确的延迟时间&#xff0c;建议使用 __nop() 函数来组合达成。__nop() 函数能够产生 1 个精确的 CPU 频率周期延迟时间。然而&…