聊一聊内存泄漏 ------在valgrind检查不出来时怎么办??
这几天多个版本出现了多个内存泄漏问题-----------------------------------------怎么办????
Q1:进程调用某库函数分配内存不释放, 但是在进程退出时,统一释放内存,valgrind 检查不出来,但是频繁调用库函数会耗尽内存。怎么快速定位那个库函数导致!!!!!除了看源码这种sa办法
Q2:某些设备不支持跑valgrind 怎么办??-
目前C&C++ 动态分配内存都是使用malloc-free new-delete
所以第一个方法是 每次分配内存时先记录下来 释放时记录下来 这样一对比就出来。。。or malloc记录地址 free 去掉记录地址
最后剩下的就是 没有释放的。。。。
第二个方法就是hook malloc了
http://www.gnu.org/savannah-checkouts/gnu/libc/manual/html_node/Hooks-for-Malloc.html
http://goog-perftools.sourceforge.net/doc/tcmalloc.html
再就是 http://jemalloc.net/jemalloc.3.html#arena.i.chunk_hooks
再或者是:https://gcc.gnu.org/onlinedocs/gcc-4.9.2/gcc/Debugging-Options.html#index-fsanitize_003daddress-593
第三个:malloc是一个weak symbol,所以直接写一个malloc同名函数就行,同名函数中可以通过符号 __libc_malloc,这个符号直接指向malloc的实现部分
--------------->GCC wrap
ld中有一个选项 –wrap,当查找某个符号时,它优先先解析__wrap_symbol, 解析不到才去解析symbol。
好像对C++的new不起作用。
extern void *__libc_malloc(size_t size); void* malloc (size_t size) { // do your stuff { } // call the original malloc return __libc_malloc(size); }
再就是mtrace 了
再就是对比之前版本---看下这个版本改了什么了。。。再或者就是看覆盖率,那些没有跑到,然后review代码了。。。
还要啥方法?????????????????????

/* Prototypes for __malloc_hook, __free_hook */ #include <malloc.h> #include<stdio.h> #include<stdlib.h> /* Prototypes for our hooks. */ static void my_init_hook (void); static void *my_malloc_hook (size_t, const void *); static void my_free_hook (void*, const void *); /* Variables to save original hooks. */ static void *(*old_malloc_hook)(size_t, const void *); static void *(*old_free_hook)(size_t, const void *); extern void *(*malloc_hook)(size_t, const void *); extern void *(*free_hook)(size_t, const void *); static void my_init (void) { old_malloc_hook = __malloc_hook; old_free_hook = __free_hook; __malloc_hook = my_malloc_hook; __free_hook = my_free_hook; } static void * my_malloc_hook (size_t size, const void *caller) { void *result; /* Restore all old hooks */ __malloc_hook = old_malloc_hook; __free_hook = old_free_hook; /* Call recursively */ result = malloc (size); /* Save underlying hooks */ old_malloc_hook = __malloc_hook; old_free_hook = __free_hook; /* printf might call malloc, so protect it too. */ printf ("malloc (%u) returns %p\n", (unsigned int) size, result); /* Restore our own hooks */ __malloc_hook = my_malloc_hook; __free_hook = my_free_hook; return result; } static void my_free_hook (void *ptr, const void *caller) { /* Restore all old hooks */ __malloc_hook = old_malloc_hook; __free_hook = old_free_hook; /* Call recursively */ free (ptr); /* Save underlying hooks */ old_malloc_hook = __malloc_hook; old_free_hook = __free_hook; /* printf might call free, so protect it too. */ printf ("freed pointer %p\n", ptr); /* Restore our own hooks */ __malloc_hook = my_malloc_hook; __free_hook = my_free_hook; } main () { my_init (); int *p = malloc(100); p[1] = 23; p[2] = 32; free(p); p = NULL; }
目前使用malloc hook 解决了 不能跑vlagrind的问题;但是只是知道有内存泄漏,那怎样知道内存泄漏时那个函数触发的呢??
继续研究堆栈回溯!!!
使用backtrace???--------测试一下

/* Prototypes for __malloc_hook, __free_hook */ #include <malloc.h> #include<stdio.h> #include<stdlib.h> /* Prototypes for our hooks. */ static void my_init_hook (void); static void *my_malloc_hook (size_t, const void *); static void my_free_hook (void*, const void *); /* Variables to save original hooks. */ static void *(*old_malloc_hook)(size_t, const void *); static void *(*old_free_hook)(size_t, const void *); extern void *(*malloc_hook)(size_t, const void *); extern void *(*free_hook)(size_t, const void *); /* Obtain a backtrace and print it to @code{stdout}. */ void print_trace (void) { void * array[10]; size_t size; char ** strings; size_t i; size = backtrace(array, 10); strings = backtrace_symbols (array, size); if (NULL == strings) { perror("backtrace_symbols"); exit(EXIT_FAILURE); } printf ("Obtained %zd stack frames--------------start.\n", size); for (i = 0; i < size; i++) printf ("%s\n", strings[i]); printf ("Obtained %zd stack frames-------end.\n", size); free(strings); strings = NULL; } static void my_init (void) { old_malloc_hook = __malloc_hook; old_free_hook = __free_hook; __malloc_hook = my_malloc_hook; __free_hook = my_free_hook; print_trace(); } static void * my_malloc_hook (size_t size, const void *caller) { void *result; /* Restore all old hooks */ __malloc_hook = old_malloc_hook; __free_hook = old_free_hook; /* Call recursively */ result = malloc (size); /* Save underlying hooks */ old_malloc_hook = __malloc_hook; old_free_hook = __free_hook; /* printf might call malloc, so protect it too. */ printf ("malloc (%u) returns %p\n", (unsigned int) size, result); /* Restore our own hooks */ __malloc_hook = my_malloc_hook; __free_hook = my_free_hook; return result; } static void my_free_hook (void *ptr, const void *caller) { /* Restore all old hooks */ __malloc_hook = old_malloc_hook; __free_hook = old_free_hook; /* Call recursively */ free (ptr); /* Save underlying hooks */ old_malloc_hook = __malloc_hook; old_free_hook = __free_hook; /* printf might call free, so protect it too. */ printf ("freed pointer %p\n", ptr); /* Restore our own hooks */ __malloc_hook = my_malloc_hook; __free_hook = my_free_hook; } main () { my_init (); int *p = malloc(100); p[1] = 23; p[2] = 32; free(p); p = NULL; }
root@test:/home#gcc malloc_hook.c -g -rdynamic -o mallochook // -rdynamic可用来通知链接器将所有符号添加到动态符号表中
root@test:/home# ./mallochook malloc (36) returns 0x4b3010 malloc (1182) returns 0x4b3450 malloc (36) returns 0x4b3900 malloc (56) returns 0x4b3930 malloc (360) returns 0x4b3970 malloc (446) returns 0x4b3ae0 Obtained 6 stack frames--------------start. ./mallochook(print_trace+0x2d) [0x401203] ./mallochook(printf_test+0x9) [0x4012d9] ./mallochook() [0x40131c] ./mallochook(main+0xd) [0x401441] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0) [0x7f77f9c4b830] ./mallochook(_start+0x29) [0x401109] Obtained 6 stack frames-------end. freed pointer 0x4b3ae0 malloc (100) returns 0x4b3ae0 freed pointer 0x4b3ae0
貌似可以
比如当前版本有改动 ,和之前的版本对比, 看代码改动之处。分析代码是否可能导致内存泄露。。。。。。。
再或者是用valgrind 时 出现了内存分配了,平时不释放, 但是退出时,会释放掉。比如mac地址表,每次mac 地址表删除时, 会分配内存记录, 但是进程统计后,没有释放。但是 使用内存越来越多。
感觉就是内存泄露,但是跑valgrind时, 由于会统一释放,最后认为跑不出来。
顺便回忆一下:valgrind使用见之前文章 https://www.cnblogs.com/codestack/p/10855687.html
常见的内存分配方式分三种:静态存储,栈上分配,堆上分配。全局变量属于静态存储,它们是在编译时就被分配了存储空间,函数内的局部变量属于栈上分配,
而最灵活的内存使用方式当属堆上分配,也叫做内存动态分配了。常用的内存动态分配函数包括:malloc, alloc, realloc, new 等,动态释放函数包括 free, delete。
Memcheck 工具主要检查下面的程序错误:
• 使用未初始化的内存 (Use of uninitialised memory)
• 使用已经释放了的内存 (Reading/writing memory after it has been free’d)
• 使用超过 malloc分配的内存空间(Reading/writing off the end of malloc’d blocks)
• 对堆栈的非法访问 (Reading/writing inappropriate areas on the stack)
• 申请的空间是否有释放 (Memory leaks – where pointers to malloc’d blocks are lost forever)
• malloc/free/new/delete申请和释放内存的匹配(Mismatched use of malloc/new/new [] vs free/delete/delete [])
• src和dst的重叠(Overlapping src and dst pointers in memcpy() and related functions)
Valgrind 的局限
Valgrind不检查静态分配数组的使用情况。(数组越界 无法检测出来 即使是在栈空间里面)
全局变量属于静态存储,它们是在编译时就被分配了存储空间 检测不出来;
所以全局数组被才内存一般都是 定义时靠近的变量踩的内存,目前通过这个思路找出来不少踩内存bug
Valgrind占用了更多的内存--可达两倍于你程序的正常使用量。如果你用Valgrind来检测使用大量内存的程序就会遇到问题,它可能会用很长的 时间来运行测试
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
2019-06-02 生活20190602