C/C++内存泄露检测
以下测试基于的gcc版本:
gcc (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
一、mtrace
1、介绍
mtrace是包含在GNU C库里一个内存调试工具。mtrace()函数为内存分配函数(malloc,realloc,free)安装hook函数,这些hook函数用于记录内存的分配与释放的跟踪信息,这些跟踪信息可用于发现内存泄露。
muntrace()函数会使已安装的hook函数失效,所以就不再对内存的分配进行跟踪。当mtrace()被调用时,它会检查环境变量MALLOC_TRACE的值,内存分配信息会记录下该环境变量所指的文件里。
通常情况下,mtrace()程序执行前调用,而muntrace不用调用,因为有些内存要在程序结束时才会释放。mtrace所产生的跟踪信息是文本文件,但不易于人理解,可通过GNU C库提供的Perl脚本来解释。为了能够得到文件的具体位置出现了内存泄露,程序需要以debug模式编译。
2、使用步骤
1)main函数所在文件包含头文件的 <mcheck.h>,main函数开头调用mtrace()
2)以debug模式编译源代码
3) 设置环境变量MALLOC_TRACE=output_file指定记录跟踪信息的文件路径(实测表明在代码里设置环境变量才有效)
4)执行可执行程序 ./test, 会生成output_file文件
5)执行GNU C提供的Perl的脚本: mtrace test output_file
3、实例
//test.c:
#include <mcheck.h>
#include <stdlib.h>
#include <stdio.h> int main(int argc, char *argv[])
{
setenv("MALLOC_TRACE","output_file",);
mtrace(); for (int j = ; j < ; j++)
malloc(); /* Never freed--a memory leak */ calloc(,); /* Never freed--a memory leak */
exit(EXIT_SUCCESS);
}
执行: gcc -g test.c -o test
./test
mtrace test output_file
检测结果:
- 0x084f8008 Free 5 was never alloc'd 0xb7617024
- 0x084f8070 Free 6 was never alloc'd 0xb76cb866
- 0x084f8090 Free 7 was never alloc'd 0xb76cb86e
Memory not freed:
-----------------
Address Size Caller
0x084f8418 0x2 at /home/zpy/tmp/test.c:10 (discriminator 2)
0x084f8428 0x2 at /home/zpy/tmp/test.c:10 (discriminator 2)
0x084f8438 0x4 at /home/zpy/tmp/test.c:14
内存泄露的大小及位置都显示出来了。
4、总结:
mtrace仅仅能检测C语言中通过malloc、realloc等分配的内存,并不能对C++中通过new分配的内存,需要对源代码重新编译才能检测。
二、memwatch
1、介绍
memwatch是一个内存泄露检测工具,其特征如下:
- 支持ANSI C
- 检测多次释放内存,以及错误的释放方式
- 检测未释放的内存
- 检测内存buffer的上溢与下溢
- 检测对野指针的写
- 部分支持C++(默认disabled)
2、使用方式:
1)下载memwatch包,解压
2)在所有需要进行检测的代码源文件中都包含 memwath.h 头文件
3)重新编译源代码,并指定宏定义MEMWATCH MEMWATCH_STDIO
4)执行程序./test
5)查看生成的文件memwatch.log内容
3、实例:
//test.c
#include <stdlib.h>
#include <stdio.h>
#include "memwatch.h"
int main(int argc, char *argv[])
{
for (int j = ; j < ; j++)
malloc(); /* Never freed--a memory leak */ calloc(,); /* Never freed--a memory leak */
exit(EXIT_SUCCESS);
}
编译: gcc -DMEMWATCH -DMW_STDIO test.c memwatch.c -o test
运行:./test
查看memwatch.log文件:
============= MEMWATCH 2.71 Copyright (C) - Johan Lindh ============= Started at Sat Apr :: Modes: __STDC__ -bit mwDWORD==(unsigned long)
mwROUNDALLOC== sizeof(mwData)== mwDataSize== Stopped at Sat Apr :: unfreed: <> test.c(), bytes at 0x92a6260 { .. .. .. .. .. .. .. .. .. .. .. .. ....}
unfreed: <> test.c(), bytes at 0x92a6228 {FE FE .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..}
unfreed: <> test.c(), bytes at 0x92a61f0 {FE FE .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..} Memory usage statistics (global):
N)umber of allocations made:
L)argest memory usage :
T)otal of all alloc() calls:
U)nfreed bytes totals :
4、总结:
memwatch能够较好地对C语言中的内存泄露进行检测,对C++ 中new分配的内存不建议采用些工具检测,因为它对C++支持不完善。使用该工具需要重新编译源代码,并需要在所有的源文件中都要包含头文件 "memwatch.h"
三、LeakTracer
1、介绍
LeakTracer是一个小型的C++内存泄露检测工具。它能够检测如下内存问题:
- 未释放的内存
- 对超出所分配内存范围外的overwritten
- 试图释放并未分配的内存(比如释放garbage pointer以及多次释放)
- 释放与分配函数的不匹配,如使用new[]分配,而使用delete释放
在使用LeakTracer时,通过提供的LeakCheck脚本运行你的程序,它使用LD_PRELOAD在你的函数上层进行“重写”。如果你的平台不支持LD_PRELOAD,则需要将LeakTracer.o 对象文件加入到Makefile文件中,然后运行你的应用程序
LeakTracer利用gdb去输出发生内存泄露所发生的位置,它是通过override operator new和operator delete来实现检测。
2、使用方法:
1)下载LeakTracer
2)解压,执行make, 会生成LeakTracer.so
3)以debug模式编译源代码
4)通过提供的LeakCheck运行程序:./LeakCheck ./test ,会生成leak.out文件
5)通过提供的leak-analyze脚本分析结果:./leak-analyze test leak.out (leak-analyze 会加载LeakTracer.so,所以注意路径)
3、实例:
// Small leaky test program void foo() {
int *x = new int;
} int main() {
int *z = new int[];
char *q = new char[];
q[] = 'x'; // MAGIC overrun
// Commenting out should make this abort
// delete q;
foo();
foo();
delete z;
delete z; // delete value twice
}
执行:
g++ -g test.cc -o test
./LeakCheck ./test
./leak-analyze test leak.out
检测结果:
Gathered ( unique) points of data.
Reading symbols from test...done.
(gdb)
#-- Alloc: Different allocation schemes
alloc here :0x8048569 is in main() (test.cc:).
int main() {
int *z = new int[];
..free here :0x804859d is in main() (test.cc:).
delete z; // delete value twice #-- Leak: counted 2x / total Size:
0x804854f is in foo() (test.cc:).
void foo() {
int *x = new int; #-- Leak: counted 1x / total Size:
0x8048579 is in main() (test.cc:).
int *z = new int[];
char *q = new char[]; #-- delete on not allocated memory: counted 1x
0x80485a9 is in main() (test.cc:).
delete z; // delete value twice
}
检测结果反映出发生内存泄露相关的代码,以及所在的文件和行号,非常Nice!
4、总结:
LeakTracer仅能够检测new/new[] 分配的内存,对于C中malloc等分配的内存无法检测。无需对对源代码进行重新编译。
四、Varlgrind
1、介绍
Valgrind是一套Linux下,开放源代码(GPL V2)的仿真调试工具的集合,其中最常用的工具是Memcheck。
Memcheck是一个内存错误检测工具,它能够检测在C/C++中普遍存在的问题:
- 对未初始化内存的使用
- 读/写释放后的内存
- 读/写超出malloc分配的内存块
- 读/写不适当的栈中内存块
- 内存泄漏,指向一块内存的指针永远丢失
- malloc/new/new[]与free/delete/delete[]等的不匹配
- memcpy()相关函数中的dst和src指针重叠
2、使用方法
valgrind [valgrind-options] your-prog [your-prog-options]
valgrind-options又分为对所有工具都适用的一些公共选项,以及仅对某个工具适用的选项。默认情况下,--tool=memcheck,也就是说默认使用工具Memcheck。
执行: valgrind ./your-grog [your-prog-options] 即可对程序进行内存检测
1)常用的公共选项:(更多详细选项:http://valgrind.org/docs/manual/manual-core.html#manual-core.options)
--tool=<toolname> [default: memcheck]
运行toolname指定的Valgrind,例如,Memcheck, Addrcheck, Cachegrind,等等。
--log-fd=<number> [default: 2, stderr]
指定Valgrind把它所有的消息都输出到一个指定的文件描述符中去。
--log-file=<filename>
指定Valgrind把它所有的信息输出到指定的文件中。
2)Memcheck常用选项:(更多详细选项:http://valgrind.org/docs/manual/mc-manual.html)
--leak-check=<no|summary|yes|full> [default: summary]
当这个选项打开时,当客户程序结束时查找内存泄漏。内存泄漏意味着有用malloc分配内存块,但是没有用free释放,而且没有指针指向这块内存。这样的内存块永远不能被程序释放,因为没有指针指向它们。如果设置为summary,Valgrind会报告有多少内存泄漏发生了。如果设置为full或yes,Valgrind给出每一个独立的泄漏的详细信息。
3、实例:
#include <stdlib.h>
#include <stdio.h> int main(int argc, char *argv[])
{
for (int j = ; j < ; j++)
malloc(); /* Never freed--a memory leak */ calloc(,); /* Never freed--a memory leak */
exit(EXIT_SUCCESS);
}
执行:valgrind --leak-check=full ./test
检测结果如下:
==== Memcheck, a memory error detector
==== Copyright (C) -, and GNU GPL'd, by Julian Seward et al.
==== Using Valgrind-3.10. and LibVEX; rerun with -h for copyright info
==== Command: ./test
====
====
==== HEAP SUMMARY:
==== in use at exit: bytes in blocks
==== total heap usage: allocs, frees, bytes allocated
====
==== bytes in blocks are definitely lost in loss record of
==== at 0x402C109: calloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==== by 0x80484BB: main (test.c:)
====
==== bytes in blocks are definitely lost in loss record of
==== at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==== by 0x804849B: main (test.c:)
====
==== LEAK SUMMARY:
==== definitely lost: bytes in blocks
==== indirectly lost: bytes in blocks
==== possibly lost: bytes in blocks
==== still reachable: bytes in blocks
==== suppressed: bytes in blocks
====
==== For counts of detected and suppressed errors, rerun with: -v
==== ERROR SUMMARY: errors from contexts (suppressed: from )
对于以上几种内存泄露的解释:
"definitely lost":确认丢失。程序中存在内存泄露,应尽快修复。当程序结束时如果一块动态分配的内存没有被释放且通过程序内的指针变量均无法访问这块内存则会报这个错误。
"indirectly lost":间接丢失。当使用了含有指针成员的类或结构时可能会报这个错误。这类错误无需直接修复,他们总是与"definitely lost"一起出现,只要修复"definitely lost"即可。
"possibly lost": 发现了一个指向某块内存中部的指针,而不是指向内存块头部。这种指针一般是原先指向内存块头部,后来移动到了内存块的中部,还有可能该指针和该内存根本就没有关系,检测工具只是怀疑有内存泄漏
"still reachable": 表示泄漏的内存在程序运行完的时候,仍旧有指针指向它,因而,这种内存在程序运行结束之前可以释放。一般情况下valgrind不会报这种泄漏,除非使用了参数 --show-reachable=yes。
4、总结:
能够较好的C/C++内存分配引起的内存泄露。无需对源代码进行重新编译,直接对二进制进行检测。
五、tcmalloc
1、介绍:
tcmalloc是一个类似于malloc的内存分配库,但同时提供了内存泄露检测与内存分析的功能。
2、使用方法
1) 首先链接libtcmalloc库,链接有两种方式:
a) 重新编译,加编译选项 -tcmalloc;
b) 无需编译,执行程序前加 LD_PRELOAD=/usr/local/libtcmalloc.so
2) 找开heap check功能:
a) 设置环境变量HEAPCHECK=normal/strict/draconian,对整个程序进行检查
b) 对部分代码进行检查:
HeapProfileLeakChecker checker("foo");
Foo(); //待检查部分
assert(checker.NoLeaks());
3) 执行程序后,即后得出检测结果
C/C++内存泄露检测的更多相关文章
- memwatch内存泄露检测工具
工具介绍 官网 http://www.linkdata.se/sourcecode/memwatch/ 其功能如下官网介绍,挑选重点整理: 1. 号称功能: 内存泄露检测 (检测未释放内存, 即 动态 ...
- Visual C++内存泄露检测—VLD工具使用说明[转]
Visual C++内存泄露检测—VLD工具使用说明 一. VLD工具概述 Visual Leak Detector(VLD)是一款用于Visual C++的免费的内存泄露检测工具.他的 ...
- 【转】c++内存泄露检测,长文慎入!
原文网址:http://blog.csdn.net/zengraoli/article/details/8905334 关于内存泄露的,今天无意想到,网上找了一下 本篇blog附带的所有工具和代码 ...
- Visual C++内存泄露检测—VLD工具使用说明
一. VLD工具概述 Visual Leak Detector(VLD)是一款用于Visual C++的免费的内存泄露检测工具.他的特点有:可以得到内存泄漏点的调用堆栈,如果可以的话,还 ...
- vld(Visual Leak Detector) 内存泄露检测工具
初识Visual Leak Detector 灵活自由是C/C++语言的一大特色,而这也为C/C++程序员出了一个难题.当程序越来越复 杂时,内存的管理也会变得越加复杂,稍有不慎就会出现内存问题.内存 ...
- Android内存泄露---检测工具篇
内存使用是程序开发无法回避的一个问题.如果我们毫不在意肆意使用,总有一天会为此还账,且痛不欲生...所以应当防患于未然,把内存使用细化到平时的每一行代码中. 内存使用概念较大,本篇先讲对已有app如何 ...
- 【YFMemoryLeakDetector】人人都能理解的 iOS 内存泄露检测工具类
背景 即使到今天,iOS 应用的内存泄露检测,仍然是一个很重要的主题.我在一年前,项目中随手写过一个简单的工具类,当时的确解决了大问题.视图和控制器相关的内存泄露,几乎都不存在了.后来想着一直就那个工 ...
- vld,Bounds Checker,memwatch,mtrace,valgrind,debug_new几种内存泄露检测工具的比较,Valgrind Cheatsheet
概述 内存泄漏(memory leak)指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况,在大型的.复杂的应用程序中,内存泄漏是常见的问题.当以前分配的一片内存不再需要使用或无法访问时,但是却 ...
- C++Builder 内存泄露检测
C++Builder 内存泄露检测 CodeGuard http://bbs.2cto.com/read.php?tid=179933 XE新版里 ReportMemoryLeaksOnShutdow ...
随机推荐
- oracle系统包——dbms_alert用法
oracle内部提供的在数据库内部和应用程序间通信的方式有以下几种:1.警报,就是DBMS_ALERT包提供的功能:2.管道,由DBMS_PIPE提供:3.高级队列,这个就很复杂,当然提供的功能也是很 ...
- 算法学习笔记之——priority queue、heapsort、symbol table、binary search trees
Priority Queue 类似一个Queue,但是按照priority的大小顺序来出队 一般存在两种方式来实施 排序法(ordered),在元素入队时即进行排序,这样插入操作为O(N),但出队为O ...
- MySql的存储引擎介绍
下面主要介绍InnoDB.MyISAM和MEMEORY三种存储引擎. InnoDB存储引擎 InnoDB遵循CNU通用公开许可(GPL)发行.InnoDB已经被一些重量级互联网公司所采用,如雅虎.Sl ...
- MySQL优化--创建索引,以及怎样索引才会生效 (03)
1. 创建索引 (看这里) 2.索引在什么情况下才会起作用(重点)
- mysql 8 root密码重置
亲测有效. https://blog.csdn.net/gupao123456/article/details/80766154
- java爬取百度首页源代码
爬虫感觉挺有意思的,写一个最简单的抓取百度首页html代码的程序.虽然简单了一点,后期会加深的. package test; import java.io.BufferedReader; import ...
- (微信小程序)二 : 创建一个页面
首先先看一下pages的目录结构吧. 我创建了一个topics页面.3个文件全创建好了之后 我往topics.js添加数据 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ...
- [android] 练习使用ListView(一)
练习使用ListView,BaseAdapter,先展示文字的,再练习图片的 MainActivity.java package com.android.test; import android.ap ...
- mysql表情存储报错问题
mysql采用utf-8字符编码,但在移动端使用输入法的表情并存储数据库的时候,出现错误. java.sql.SQLException: Incorrect string value: '\xF0\x ...
- Linux下剪切拷贝命令
Linux下剪切拷贝命令 命令格式: mv source dest mv: 命令字 source: 源文件 dest: 目的地址 Linux下拷贝命令 命令格式:cp ...