gtest:http://code.google.com/p/googletest/,可以下载最新的代码。下载后,可以参考gtest-1.6.0\make\Makefile写自己的Makefile。
程序内存的信息(/proc/self/smaps):
VMSIZE: 15316 KB
RSS: 2560 KB total
1152 KB shared
428 KB private clean
980 KB private dirty
RSS(private dirty)最接近程序所使用的内存,特别是从heap分配的内存。
使用单元测试可以检测内存泄漏。思路如下:
当然目标函数是申请了内存,然后释放内存,在生命周期结束时应该要释放它的内存。
从顶级函数开始,或者从任意可能泄漏的函数开始,一直定位到内存泄漏的位置。可以使用utest中的mock来加快内存泄漏的速度。
获取内存信息的代码(memview.cpp):http://blog.csdn.net/winlinvip/article/details/7794558
在gtest-1.6.0同目录下,写Makefile如下:
# A sample Makefile for building Google Test and using it in user
# tests. Please tweak it to suit your environment and project. You
# may want to move it to your project's root directory.
#
# SYNOPSIS:
#
# make [all] - makes everything.
# make TARGET - makes the given target.
# make clean - removes all files generated by make.
# Please tweak the following variable definitions as needed by your
# project, except GTEST_HEADERS, which you can use in your own targets
# but shouldn't modify.
# Points to the root of Google Test, relative to where this file is.
# Remember to tweak this if you move this file.
GTEST_DIR = gtest-1.6.0
# Where to find user code.
USER_DIR = .
# Flags passed to the preprocessor.
CPPFLAGS += -I$(GTEST_DIR)/include
# Flags passed to the C++ compiler.
CXXFLAGS += -g -Wall -Wextra -O0
# All tests produced by this Makefile. Remember to add new tests you
# created to the list.
TESTS = winlin_mem_leak_utest
# All Google Test headers. Usually you shouldn't change this
# definition.
GTEST_HEADERS = $(GTEST_DIR)/include/gtest/*.h \
$(GTEST_DIR)/include/gtest/internal/*.h
# House-keeping build targets.
all : $(TESTS)
clean :
rm -f $(TESTS) gtest.a gtest_main.a *.o
# Builds gtest.a and gtest_main.a.
# Usually you shouldn't tweak such internal variables, indicated by a
# trailing _.
GTEST_SRCS_ = $(GTEST_DIR)/src/*.cc $(GTEST_DIR)/src/*.h $(GTEST_HEADERS)
# For simplicity and to avoid depending on Google Test's
# implementation details, the dependencies specified below are
# conservative and not optimized. This is fine as Google Test
# compiles fast and for ordinary users its source rarely changes.
gtest-all.o : $(GTEST_SRCS_)
$(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \
$(GTEST_DIR)/src/gtest-all.cc
gtest_main.o : $(GTEST_SRCS_)
$(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \
$(GTEST_DIR)/src/gtest_main.cc
gtest.a : gtest-all.o
$(AR) $(ARFLAGS) $@ $^
gtest_main.a : gtest-all.o gtest_main.o
$(AR) $(ARFLAGS) $@ $^
# Builds a sample test. A test should link with either gtest.a or
# gtest_main.a, depending on whether it defines its own main()
# function.
winlin_mem_leak_utest.o : $(USER_DIR)/winlin_mem_leak_utest.cpp $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/winlin_mem_leak_utest.cpp
winlin_mem_leak_utest : winlin_mem_leak_utest.o gtest_main.a
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#include "gtest/gtest.h"
using namespace testing;
// less
#define AssertLess(a, b)\
EXPECT_TRUE(a < b); \
if(a >= b){ \
cout << "(" << #a << ")" \
<< "(" << a << ")" \
<< " < " \
<< "(" << #b << ")" \
<< "(" << b << ")" \
<< " failed!" \
<< endl; \
}
#define LoopAssertLess(exit, a, b)\
exit = (a >= b) ? true : exit; \
AssertLess(a, b);
// greater
#define AssertGreater(a, b)\
EXPECT_TRUE(a > b); \
if(a < b){ \
cout << "(" << #a << ")" \
<< "(" << a << ")" \
<< " > " \
<< "(" << #b << ")" \
<< "(" << b << ")" \
<< " failed!" \
<< endl; \
}
#define LoopAssertGreater(exit, a, b)\
exit = (a < b) ? true : exit; \
AssertGreater(a, b);
// the memory leak size, in KB.
// default is 1024(1MB), if the program leak 1MB, we think it's a leak!.
#define MemoryLeakSize 1024
// the biger this value, the more memory leak canbe detected(take more time also).
#define MemoryLeakDetectLoop 1000
// begin the memory leak test loop.
// usage: BeginLoopMemLeakTest()
// loop 1,000 times. (detect 1000byte leak to 1M).
#define BeginLoopMemLeakTest()\
BeginLoopMemLeakTestCount(MemoryLeakDetectLoop)
//
// loop 10,000 times. (detect 100byte leak to 1M).
#define BeginLoopMemLeakTest2() \
BeginLoopMemLeakTestCount(MemoryLeakDetectLoop*10)
//
// loop 50,000 times (detect 10byte leak to 1M).
#define BeginLoopMemLeakTest3()\
BeginLoopMemLeakTestCount(MemoryLeakDetectLoop*50)
//
// loop 500,000 times (detect 1byte leak to 1M).
#define BeginLoopMemLeakTest4()\
BeginLoopMemLeakTestCount(MemoryLeakDetectLoop*500)
//
// loop 5,000,000 times
#define BeginLoopMemLeakTest5()\
BeginLoopMemLeakTestCount(MemoryLeakDetectLoop*5000)
#define BeginLoopMemLeakTestCount(loop_count)\
MemView __a(0); \
bool __exit = false; \
int __alloc_once_size = 0;/*the normal alloc size.*/ \
for(int __i = 0; __i < loop_count && !__exit; __i++){ \
if(true){
// end the memory leak test loop.
// usage: EndLoopMemLeakTest()
// first time, the heap memory will totally free when pool delete it.
// second time, the memory will not free.
// third time, use the previous free memory.
// so here, if the memory is constant, we think it's ok and no memory leak.
#define EndLoopMemLeakTest()\
} \
MemView __c(0);\
if(__alloc_once_size == 0){ \
__alloc_once_size = __c.private_dirty - __a.private_dirty; \
} \
LoopAssertLess(__exit, __c.private_dirty - __a.private_dirty, __alloc_once_size + MemoryLeakSize);\
if(__exit){ \
cout << "leak detected loop #" << __i << endl;/**/ \
} \
}
#include "memview.cpp"
TEST(SimpleTest, MemoryLeakDetect){
BeginLoopMemLeakTest3()
new char[1]; // memory leak here
EndLoopMemLeakTest()
}
运行3万次可以检测到1个字节的泄漏。结果如下:
可运用在实际项目中。
另外,gperftools也可以检测内存泄漏:http://google-perftools.googlecode.com/svn/trunk/doc/heap_checker.html