这几天开始测试多线程的内存泄露问题,用到的工具就是Valgrind,这个工具业内还是比较出名的,用来查内存泄露,还是不错的。废话不多说,我们先从安装开始。Ubuntu环境下,运行如下命令
sudo apt-get install valgrind
安装结束以后就可以愉快的使用了。我们以下面的代码为例:
DECLARE_SIMPLE_CLASS(MyThread) IMPLEMENTS(Thread) {
public:
void run() {
printf("abc");
}
};
int main() {
MyThread t = createMyThread();
t->start();
}
使用下面的命令:
valgrind --leak-check=full --show-reachable=yes --trace-children=yes ./mytest
运行结果:
==5152== 304 bytes in 1 blocks are possibly lost in loss record 15 of 15
==5152== at 0x4C31B25: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5152== by 0x40134A6: allocate_dtv (dl-tls.c:286)
==5152== by 0x40134A6: _dl_allocate_tls (dl-tls.c:530)
==5152== by 0x64DC227: allocate_stack (allocatestack.c:627)
==5152== by 0x64DC227: pthread_create@@GLIBC_2.2.5 (pthread_create.c:644)
==5152== by 0x527E50D: obotcha::_KeepAliveThread::start() (Thread.cpp:122)
==5152== by 0x527F31B: obotcha::_Thread::_Thread(obotcha::sp<obotcha::_String>, obotcha::sp<obotcha::_Runnable>) (Thread.cpp:258)
==5152== by 0x527EF91: obotcha::_Thread::_Thread() (Thread.cpp:243)
==5152== by 0x114F8A: _MyThread::_MyThread() (ThreadTest.cpp:27)
==5152== by 0x11503B: obotcha::sp<_MyThread> createMyThread<>() (ThreadTest.cpp:27)
==5152== by 0x114E5D: main (ThreadTest.cpp:42)
==5152==
==5152== LEAK SUMMARY:
==5152== definitely lost: 20 bytes in 1 blocks
==5152== indirectly lost: 0 bytes in 0 blocks
==5152== possibly lost: 304 bytes in 1 blocks
==5152== still reachable: 677 bytes in 13 blocks
==5152== suppressed: 0 bytes in 0 blocks
valgrind发现pthread_create有内存泄露~~~~。额,这个当时的确让人崩溃。thread结束以后,貌似还有一小块内存一直没有被释放。这个该如何办呢?上网查了一下,原来,如果当前线程没有被设定成DETACHED的话,线程结束后,需要使用pthread_join来触发该一小段内存回收。参考之前Thread的设计,我们虽然谁然使用了一个KeepAliveThread来单独做pthread_cancel的处理,但是的确没有用pthread_join来做等待。那这样就会导致上面的问题。
参考keepAliveThread,我们又添加了一个releaseThread来触发每个需要释放的thread的join,强行释放内存即可。相关代码如下:
static void* freethreadmem(void *th) {
_ReleaseThread *thread = static_cast<_ReleaseThread *>(th);
thread->run();
return nullptr;
}
_ReleaseThread::_ReleaseThread() {
mutex = createMutex("ReleaseThreadMutex");
cond = createCondition();
mThreadPids = createArrayList<Uint64>();
mStartBarrier = createAtomicInteger(0);
}
_ReleaseThread::~_ReleaseThread() {
}
void _ReleaseThread::stop() {
Uint64 poison;
sendRelease(poison);
pthread_join(mTid,nullptr);
}
void _ReleaseThread::sendRelease(Uint64 t) {
AutoMutex ll(mutex);
mThreadPids->add(t);
cond->notify();
}
void _ReleaseThread::start() {
AutoMutex l(mutex);
pthread_attr_init(&mAttr);
pthread_create(&mTid, &mAttr, freethreadmem, this);
while(mStartBarrier->orAndGet(0) == 0) {
//wait
}
}
在KeepAliveThread移除线程的同时,把pthread_t传递给release线程,去做join的处理
mReleaseThread->sendRelease(t); //新添加
tLocal->remove(t->toValue());
本地实测OK。关于内存泄露的检测,喷血推荐valgrind,网上说的mtrace和dmalloc建议不要去用,到处都是坑~。