存泄漏檢測組件)
1.內(nèi)存泄漏a.是否有內(nèi)存泄漏 b.在哪里有內(nèi)存泄漏2.try-catch調(diào)用malloc 沒有調(diào)用free#includestdio.h#includestdlib.hintmain(){void*p1malloc(5);void*p2malloc(10);void*p3malloc(15);free(p1);free(p3);return0;}上面這個程序造成了內(nèi)存泄漏void*_malloc(size_tsize){printf(_malloc\n);}void_free(void*ptr){printf(_free\n);}#definemalloc(size)_malloc(size)#definefree(ptr)_free(ptr)intmain(){void*p1malloc(5);void*p2malloc(10);void*p3malloc(15);free(p1);free(p3);return0;}可以根據(jù)打印值判斷malloc和free個數(shù)不匹配為了得到更詳細(xì)的信息我們可以將文件名和行號打印出來void*_malloc(size_tsize,constchar*filename,intline){void*ptrmalloc(size);printf([]_malloc: %p, filename: %s, line: %d\n,ptr,filename,line);returnptr;}void_free(void*ptr,constchar*filename,intline){printf([-]_free, filename: %s, line: %d\n,filename,line);free(ptr);}#definemalloc(size)_malloc(size,__FILE__,__LINE__)#definefree(ptr)_free(ptr,__FILE__,__LINE__)為了輸出信息更直觀我們可以在malloc時創(chuàng)建一個文件free時刪除這個文件最后看看是否有文件生成就可知道是否發(fā)生內(nèi)存泄漏void*_malloc(size_tsize,constchar*filename,intline){void*ptrmalloc(size);charbuff[128]{0};sprintf(buff,./mem/%p.mem,ptr);FILE*fpfopen(buff,w);fprintf(fp,[]addr: %p, filename: %s, line: %d\n,ptr,buff,line);fflush(fp);fclose(fp);//printf([]_malloc: %p, filename: %s, line: %d\n, ptr, filename, line);returnptr;}void_free(void*ptr,constchar*filename,intline){charbuff[128]{0};sprintf(buff,./mem/%p.mem,ptr);if(unlink(buff)0){printf(double free: %p\n,ptr);return;}//printf([-]_free, filename: %s, line: %d\n, filename, line);returnfree(ptr);}進(jìn)入mem目錄可以看到0x5601fae8f4b0.mem查看文件內(nèi)容可以看到更詳細(xì)的泄漏內(nèi)容也可以使用hook技術(shù)typedefvoid*(*malloc_t)(size_tsize);malloc_tmalloc_fNULL;typedefvoid(*free_t)(void*ptr);free_tfree_fNULL;void*malloc(size_tsize){printf(malloc \n);}voidfree(void*ptr){printf(free \n);}voidinit_hook(void){if(!malloc_f){malloc_fdlsym(RTLD_NEXT,malloc);}if(!free_f){free_fdlsym(RTLD_NEXT,free);}}intmain(){init_hook();void*p1malloc(5);void*p2malloc(10);void*p3malloc(15);free(p1);free(p3);return0;}但是運(yùn)行該程序會發(fā)現(xiàn)發(fā)生了segmentation fault這時因?yàn)閜rintf本身也會調(diào)用malloc造成了遞歸調(diào)用。intenable_malloc_hook1;intenable_free_hook1;void*malloc(size_tsize){void*ptrNULL;if(enable_malloc_hook){enable_malloc_hook0;printf(malloc \n);ptrmalloc_f(size);enable_malloc_hook1;}else{ptrmalloc_f(size);}returnptr;}voidfree(void*ptr){if(enable_free_hook){enable_free_hook0;printf(free \n);enable_free_hook1;}else{free_f(ptr);}}可以做一個修改讓printf調(diào)用只調(diào)用一次。這樣就不會遞歸調(diào)用了。我們?nèi)匀豢梢栽趍alloc時創(chuàng)建一個文件在free時刪除相應(yīng)的文件void*malloc(size_tsize){void*ptrNULL;if(enable_malloc_hook){enable_malloc_hook0;printf(malloc \n);ptrmalloc_f(size);charfilename[128]{0};sprintf(filename,./mem/%p.mem,ptr);FILE*fpfopen(filename,w);fprintf(fp,[]addr: %p, filename: %s, line: %d,ptr,__FILE__,__LINE__);enable_malloc_hook1;}else{ptrmalloc_f(size);}returnptr;}但是這時你會發(fā)現(xiàn)我們打印的行號信息始終不變而之前是宏定義會在使用的地方展開但是這里是一個函數(shù)所以行號不會跟隨使用的地方發(fā)生變化。解決這個問題可以使用__builtin_return_address這個函數(shù)是編譯器自帶的函數(shù)void*malloc(size_tsize){void*ptrNULL;if(enable_malloc_hook){enable_malloc_hook0;printf(malloc \n);ptrmalloc_f(size);//0參數(shù)表示上一級 1向上反二級//main - f1() - f2() - f3() {}void*caller__builtin_return_address(0);charfilename[128]{0};sprintf(filename,./mem/%p.mem,ptr);FILE*fpfopen(filename,w);fprintf(fp,[]caller: %p, addr: %p, size: %ld,caller,ptr,size);fflush(fp);enable_malloc_hook1;}else{ptrmalloc_f(size);}returnptr;}voidfree(void*ptr){if(enable_free_hook){enable_free_hook0;charbuff[128]{0};sprintf(buff,./mem/%p.mem,ptr);if(unlink(buff)0){printf(double free: %p\n,ptr);return;}free_f(ptr);enable_free_hook1;}else{free_f(ptr);}}這時再查看文件內(nèi)容雖然打印出了地址但還是不直觀這里用到一個工具addr2line可以通過addr2line -f -e ./memleak -a 0x5595d3a06bcc查看文件和行號還有一種通過libc的方式更底層的方式因?yàn)閙alloc底層調(diào)用的是__libc_mallocexternvoid*__libc_malloc(size_tsize);externvoid__libc_free(void*ptr);intenable_malloc_hook1;intenable_free_hook1;void*malloc(size_tsize){void*ptrNULL;if(enable_malloc_hook){enable_malloc_hook0;printf(malloc \n);ptr__libc_malloc(size);//0參數(shù)表示上一級 1向上反二級//main - f1() - f2() - f3() {}void*caller__builtin_return_address(0);charfilename[128]{0};sprintf(filename,./mem/%p.mem,ptr);FILE*fpfopen(filename,w);fprintf(fp,[]caller: %p, addr: %p, size: %ld,caller,ptr,size);fflush(fp);enable_malloc_hook1;}else{ptr__libc_malloc(size);}returnptr;}voidfree(void*ptr){if(enable_free_hook){enable_free_hook0;charbuff[128]{0};sprintf(buff,./mem/%p.mem,ptr);if(unlink(buff)0){printf(double free: %p\n,ptr);return;}__libc_free(ptr);enable_free_hook1;}else{__libc_free(ptr);}}try-catch#includestdio.h#includesetjmp.hjmp_buf env;voidfunc(intidx){printf(func -- idx: %d\n,idx);longjmp(env,idx);}intmain(){intcountsetjmp(env);if(count0){printf(count - %d\n,count);func(count);}elseif(count1){printf(count - %d\n,count);func(count);}elseif(count2){printf(count - %d\n,count);func(count);}elseif(count3){printf(count - %d\n,count);func(count);}printf(other count : %d\n,count);return0;}程序輸出count - 0 func -- idx: 1 count - 1 func -- idx: 2 count - 2 func -- idx: 3 count - 3 func -- idx: 4 other count : 4#includestdio.h#includesetjmp.h#defineTRYintcountsetjmp(env);if(count0)#defineCATCH(x)elseif(count(x))#defineTHROW(idx)longjmp(env,(idx))#defineFINALLYjmp_buf env;voidfunc(intidx){printf(func -- idx: %d\n,idx);THROW(idx);}intmain(){TRY{printf(count - %d\n,count);func(count);}CATCH(1){printf(count - %d\n,count);func(count);}CATCH(2){printf(count - %d\n,count);func(count);}CATCH(3){printf(count - %d\n,count);func(count);}FINALLY{printf(other count : %d\n,count);}return0;}但同時存在兩個問題try/catch嵌套用單鏈表頭插法線程安全問題pthread_key_t文章參考于零聲教育的C/Clinux服務(wù)期高級架構(gòu)系統(tǒng)教程學(xué)習(xí):https://ke.qq.com/course/417774?flowToken1020253