最近查项目linux工程的内存泄露问题时,发现VIRT内存涨的特别厉害,开20线运行12个多小时,内存涨了70多个G,吓死个人,最后通过查阅资料和博客,发现是下面的情况导致的。
情况说明:
main
{
for(i=0;i
{
pthread_attr_t threadAttr;
pthread_attr_init(&threadAttr);
// Set the stack size of the thread
pthread_attr_setstacksize(&threadAttr, 120*1024);
//The default stack size is 2M !
pthread_create(&(Threadhandle[i]), NULL, InstanceThreadProc, intancePara+i);
pthread_attr_destroy(&threadAttr);
}
........
for(i=0;i
printf("thread %d - ok\n",i);
pthread_join(Threadhandle[i], NULL);
}
}
VOID InstanceThreadProc(PVOID pvoid)
{
while(1)
{
sem_init(&(pollpara.hStop),0,0);
sem_init(&(pollpara.pollStoped),0,0);
pthread_attr_t threadAttr;
pthread_attr_init(&threadAttr);
pthread_attr_setstacksize(&threadAttr, 120*1024);
pthread_create(&Threadhandle, NULL, PollingThread,&pollpara);
pthread_attr_destroy(&threadAttr);
}
......
sem_wait(&pollpara.hStop);
}
VOID PollingThread (PVOID pvoid)
{
//其他操作和处理
。。。。。
sem_post(&(pPara->hStop));
}
出问题的地方:
1. InstanceThreadProc线程中不断的创建线程PollingThread
2.线程同步机制sem只是负责同步或通知,并不负责线程资源的释放
也即是说即使线程InstanceThreadProc能够等待(使用sem)pollingThread线程正确退出,但是由于在Linux下,使用pthread_create建立的线程默认是joinable属性的,如果不调用pthread_join等待该线程结束的话,系统为pollingThread开辟的内存资源无法回收,导致内存泄露。
修改方案
1.在InstanceThreadProc中使用pthread_join等待线程结束
2.在创建线程pollingThread的时候,将其属性设置为PTHREAD_CREATE_DETACHED,这样线程结束后,系统会自动回线程资源,但是此种情况下,不能使用pthread_join来等待线程结束
3.在线程pollingThread函数的开头,调用pthread_detach(pthread_self()),表示在线程结束后会自行释放 自身所占用的资源。
总结
在Linux中,默认情况下是在一个线程被创建后,必须使用pthread_join函数对创建的线程进行资源回收,但是可以设置Threads attributes来设置当一个线程结束时,直接回收此线程所占用的系统资源。
在Linux下,使用pthread_create建立的线程默认是joinable属性的,如果不调用pthread_join等待该线程结束,那么即便该线程调用pthread_exit使线程函数退出后, 线程本身的资源仍不会释放,这样线程资源就不会释放,导致内存泄露出现。