1 前言

mtrace(memory trace),是 GNU Glibc 自带的内存问题检测工具,它可以用来协助定位内存泄露问题。它的实现源码在glibc源码的malloc目录下,其基本设计原理为设计一个函数 void mtrace (),函数对 libc 库中的 malloc/free 等函数的调用进行追踪,由此来检测内存是否存在泄漏的情况。

上篇讲到如何使用 mtrace 检查可执行程序中的内存泄漏,可以定位到源码的行数,但是存在一个问题,它没办法直接显示动态库所在的源码行数,而 Linux 开发动态库的使用是十分常见的,那么该篇就讲讲 mtrace 如何定位动态库中的内存泄漏问题。


2 使用方式

首先我们需要在当前目录下创建两个文件(一个编译成动态库,另一个编译成可执行文件)

2.1 源码示例

inter.c 动态库源码

#include <stdlib.h>
#include <stdio.h> void InterTest(void)
{
int *p = (int *)malloc(10 * sizeof(int)); printf("InterTest: p = %p\n", p);
}

编译动态库(-g 必须的,不然定位源码位置都是 ???)

gcc -g inter.c -fPIC -shared -o libinter.so

可执行文件 test.c(和上篇中的测试代码比较,多个动态库的接口调用和睡眠等待时间)

#include <mcheck.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h> // 测试代码,没有接口头文件,所以使用 extern
extern void InterTest(void); int main(int argc, char **argv)
{
mtrace(); // 开始跟踪 char *p = (char *)malloc(100); free(p);
p = NULL; InterTest(); p = (char *)malloc(100); muntrace(); // 结束跟踪,并生成日志信息 int wait = 20; //等待的目的是方便后面操作
while (wait--)
{
sleep(1);
printf("wait = %d\n", wait);
} return 0;
}

编译成可执行文件

gcc -g test.c -L"/home/const/workspace/memtest" -linter -o test

2.2 运行程序

首先先设置生成跟踪的日志路径

export MALLOC_TRACE=./test.log

接着执行程序,同时 ps 查看当前可执行程序的 PID

./test &  // & 的作用是后台运行,方便在等待期间进行 ps 等操作
const@server:~/workspace/memtest$ ps

  PID TTY          TIME CMD
1631 pts/62 00:00:00 bash
10723 pts/62 00:00:00 test
10745 pts/62 00:00:00 ps

可以看到此时的 test 执行程序的 PID 为 10745,接着输入以下指令查看加载的动态库信息(确保 test 还在执行)

const@server:~/workspace/memtest$ cat /proc/10723/maps

00400000-00401000 r-xp 00000000 08:01 144706317                          /home/const/workspace/memtest/test
00600000-00601000 r--p 00000000 08:01 144706317 /home/const/workspace/memtest/test
00601000-00602000 rw-p 00001000 08:01 144706317 /home/const/workspace/memtest/test
021f8000-02219000 rw-p 00000000 00:00 0 [heap]
7f59842e3000-7f59844a3000 r-xp 00000000 08:16 4723539 /lib/x86_64-linux-gnu/libc-2.23.so
7f59844a3000-7f59846a3000 ---p 001c0000 08:16 4723539 /lib/x86_64-linux-gnu/libc-2.23.so
7f59846a3000-7f59846a7000 r--p 001c0000 08:16 4723539 /lib/x86_64-linux-gnu/libc-2.23.so
7f59846a7000-7f59846a9000 rw-p 001c4000 08:16 4723539 /lib/x86_64-linux-gnu/libc-2.23.so
7f59846a9000-7f59846ad000 rw-p 00000000 00:00 0
7f59846ad000-7f59846ae000 r-xp 00000000 08:01 144706316 /home/const/workspace/memtest/libinter.so
7f59846ae000-7f59848ad000 ---p 00001000 08:01 144706316 /home/const/workspace/memtest/libinter.so
7f59848ad000-7f59848ae000 r--p 00000000 08:01 144706316 /home/const/workspace/memtest/libinter.so
7f59848ae000-7f59848af000 rw-p 00001000 08:01 144706316 /home/const/workspace/memtest/libinter.so
7f59848af000-7f59848d5000 r-xp 00000000 08:16 4723525 /lib/x86_64-linux-gnu/ld-2.23.so
7f5984a9e000-7f5984aa1000 rw-p 00000000 00:00 0
7f5984ad3000-7f5984ad4000 rw-p 00000000 00:00 0
7f5984ad4000-7f5984ad5000 r--p 00025000 08:16 4723525 /lib/x86_64-linux-gnu/ld-2.23.so
7f5984ad5000-7f5984ad6000 rw-p 00026000 08:16 4723525 /lib/x86_64-linux-gnu/ld-2.23.so
7f5984ad6000-7f5984ad7000 rw-p 00000000 00:00 0
7fffedca8000-7fffedcca000 rw-p 00000000 00:00 0 [stack]
7fffedde7000-7fffeddea000 r--p 00000000 00:00 0 [vvar]
7fffeddea000-7fffeddec000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]

2.3 分析定位

首先输入指令得到内存泄漏信息

const@server:~/workspace/memtest$ mtrace test ./test.log

Memory not freed:
-----------------
Address Size Caller
0x00000000021f8450 0x64 at /home/const/workspace/memtest/test.c:19
0x00000000021f84c0 0x28 at 0x7f59846ad702
0x00000000021f84f0 0x400 at 0x7f59843501d5

从日志文件中可以看到,可执行文件的内存泄漏直接就显示了源码的具体位置,而动态库中的泄漏没有具体显示,只是机器码的地址信息,则 libinter.so 的加载地址为 0x7f59846ad000-0x7f59848af000,其中上述符合的为 0x7f59846ad702,减去 libinter.so 的 base 地址 0x7f59846ad000得到相对偏移地址为 0x702。

通过使用 "addr2line" 命令工具,得到动态库源文件的行数,定位内存泄漏的位置。

const@server:~/workspace/memtest$ addr2line -e libinter.so 0x702

/home/const/workspace/memtest/inter.c:6

至于最后一行的 0x00000000021f84f0    0x400  at 0x7f59843501d5,通过地址比较不难看出是 /lib/x86_64-linux-gnu/libc-2.23.so 中的内存信息,通过上述相同的操作打印的内容可能是 ??,原因是没有 -g 编译后的调试信息;这个其实可以忽略,标准库中基本不会存在这种问题,这种属于可执行程序运行结束后相关资源(后期自动回收处理)还没有及时释放(可以屏蔽动态库函数的调用和睡眠函数,这个就不存在了)。

内存泄漏定位工具之 mtrace(二)的更多相关文章

  1. 内存泄漏定位工具之 valgrind 使用

    1 前言 前面介绍了 GCC 自带的 mtrace 内存泄漏检查工具,该篇主要介绍开源的内存泄漏工具 valgrind,valgrind 是一套 Linux 下,开放源代码的动态调试工具集合,能够检测 ...

  2. 内存泄漏分析工具tMemMonitor (TMM)使用简介

    C/C++由于灵活.高效的优点一直以来都是主流的程序设计语言之一,但是其内存的分配与释放均由程序员自己管理,当由于疏忽或错误造成程序未能释放不再使用的内存时就会造成内存泄漏.在大型.复杂的应用程序中, ...

  3. Cocos开发中性能优化工具介绍之Visual Studio内存泄漏检测工具——Visual Leak Detector

    那么在Windows下有什么好的内存泄漏检测工具呢?微软提供Visual Studio开发工具本身没有什么太好的内存泄漏检测功能,我们可以使用第三方工具Visual Leak Detector(以下简 ...

  4. C++内存泄漏检测工具

    C++内存泄漏检测工具 1.VC自带的CRT:_CrtCheckMemory   调试器和 CRT 调试堆函数 1.1用法: /************************************ ...

  5. C/C++的内存泄漏检测工具Valgrind memcheck的使用经历

    Linux下的Valgrind真是利器啊(不知道Valgrind的请自觉查看参考文献(1)(2)),帮我找出了不少C++中的内存管理错误,前一阵子还在纠结为什么VS 2013下运行良好的程序到了Lin ...

  6. 构造函数,C++内存管理,内存泄漏定位

    构造函数 1.构造顺序 虚基类构造函数,基类构造函数,类对象构造函数,自己的构造函数 2.必须使用初始化列表 (1) 引用成员,常量成员: (2) 基类没默认构造函数(自己重载覆盖了), (3)类对象 ...

  7. android 内存泄漏检测工具 LeakCanary 泄漏金丝雀

    韩梦飞沙 yue31313 韩亚飞 han_meng_fei_sha 313134555@qq.com 内存泄漏检测工具 android 内存泄漏检测工具 ======== 内存泄漏 就是  无用的对 ...

  8. Cocos性能优化工具的开发介绍Visual Studio内存泄漏检测工具——Visual Leak Detector

    然后,Windows下有什么好的内存泄漏检測工具呢?微软提供Visual Studio开发工具本身没有什么太好的内存泄漏检測功能.我们能够使用第三方工具Visual Leak Detector(下面简 ...

  9. 介绍两个非常好用的Javascript内存泄漏检测工具

    内存泄漏对开发者来说一般很难检测因为它们是由一些大量代码中的意外的错误引起的,但它在系统内存不足前并不影响程序的功能.这就是为什么会有人在很长时间的测试期中收集应用程序性能指标来测试性能. 最简单的检 ...

  10. 内存泄漏检测工具VLD在VS2010中的使用举例

    Visual LeakDetector(VLD)是一款用于Visual C++的免费的内存泄露检测工具.它的特点有:(1).它是免费开源的,采用LGPL协议:(2).它可以得到内存泄露点的调用堆栈,可 ...

随机推荐

  1. 【Qt】开源一键代码开光神器,一行代码给你的项目施加祝福,减少Bug

    年底啦,没什么项目,想摸鱼划水没见到什么好玩的东西,看到有人分享这个,直接做个库来玩下,之后说不定会嵌到公司的项目里面去.... 效果如下,佛光普照! 输入也只需要一行命令 magic_spells: ...

  2. 每天学五分钟 Liunx 100 | 存储篇:磁盘分区

    这一节主要介绍 Liunx 是怎么用磁盘的. 磁盘分区 在 Liunx 中一切皆文件,磁盘在 Liunx 中也是文件,包括 /dev/hd[a-d](以 IDE 为接口) 和 /dev/sd[a-p] ...

  3. 深入理解Kafka核心设计及原理(六):Controller选举机制,分区副本leader选举机制,再均衡机制

    转载请注明出处:https://www.cnblogs.com/zjdxr-up/p/15026824.html 目录: 6.1.Kafka核心总控制器Controller 6.2.Controlle ...

  4. 如何让Dec-C++支持C++11

    1.问题 Dev-C++默认设置中是不支持C++11版本特性的,如Lambda表达式,nullptr等均不提供支持 2.解决 设置编译选项 编译时加上命令-std==c++11即可

  5. SSM整合 - 环境配置

    pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="htt ...

  6. 阿里云IPV6 创建虚拟机的过程

    阿里云IPV6 创建虚拟机的过程 背景 IPV6 已经越来越广泛的应用. 想在外网开通一下IPV6,发现还有一些坑. 这里总结一下. 备忘. 开通方式 1. 登录阿里云的控制台, 打开云服务器ECS的 ...

  7. pgcacher 的简单学习

    pgcacher 的简单学习 学习地址 https://github.com/rfyiamcool/pgcacher https://zhuanlan.zhihu.com/p/551833981 ht ...

  8. [转帖]金仓数据库KingbaseES数据目录结构

    KingbaseES数据库结构 [kingbase@postgresV8]$ tree -LP2data/ . ├── data │ ├── base # 存储用户创建的数据库文件及隶属于用户数据库的 ...

  9. [转帖]Kafka关键参数设置

    https://www.cnblogs.com/wwcom123/p/11181680.html 生产环境中使用Kafka,参数调优非常重要,而Kafka参数众多,我们的java的Configurat ...

  10. [转帖]gdb调试常见命令详细总结(附示例操作)

    一.简介 通过gdb调试我们可以监控程序执行的每一个细节,包括变量的值.函数的调用过程.内存中数据.线程的调度等,从而发现隐藏的错误或者低效的代码,程序的调试过程主要有:单步执行,跳入函数,跳出函数, ...