
1.內存泄漏a.是否有內存泄漏 b.在哪里有內存泄漏2.try-catch調用malloc 沒有調用free#includestdio.h#includestdlib.hintmain(){void*p1malloc(5);void*p2malloc(10);void*p3malloc(15);free(p1);free(p3);return0;}上面這個程序造成了內存泄漏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;}可以根據打印值判斷malloc和free個數不匹配為了得到更詳細的信息我們可以將文件名和行號打印出來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時創建一個文件free時刪除這個文件最后看看是否有文件生成就可知道是否發生內存泄漏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);}進入mem目錄可以看到0x5601fae8f4b0.mem查看文件內容可以看到更詳細的泄漏內容也可以使用hook技術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;}但是運行該程序會發現發生了segmentation fault這時因為printf本身也會調用malloc造成了遞歸調用。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調用只調用一次。這樣就不會遞歸調用了。我們仍然可以在malloc時創建一個文件在free時刪除相應的文件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;}但是這時你會發現我們打印的行號信息始終不變而之前是宏定義會在使用的地方展開但是這里是一個函數所以行號不會跟隨使用的地方發生變化。解決這個問題可以使用__builtin_return_address這個函數是編譯器自帶的函數void*malloc(size_tsize){void*ptrNULL;if(enable_malloc_hook){enable_malloc_hook0;printf(malloc \n);ptrmalloc_f(size);//0參數表示上一級 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);}}這時再查看文件內容雖然打印出了地址但還是不直觀這里用到一個工具addr2line可以通過addr2line -f -e ./memleak -a 0x5595d3a06bcc查看文件和行號還有一種通過libc的方式更底層的方式因為malloc底層調用的是__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參數表示上一級 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服務期高級架構系統教程學習:https://ke.qq.com/course/417774?flowToken1020253