内存泄漏原因内存泄漏在c/c++这种不带gc(garbage collection)的语言里,是一个经常发生的问题。因为没有gc,所以分配的内存需要程序员自己调用释放。内存泄漏的根本原因是程序对于在申请的内存没有进行释放。
{void *p1 = malloc(10);void *p2 = malloc(20);free(p1);}上面的代码段,申请了两块内存p1,p2,只释放了p1,没有释放p2,产生了内存泄漏。
内存泄漏会产生哪些后果?随着程序运行时间越来越久,内存有分配没有释放,会使得进程堆中的内存会越来越少,直到耗尽。会造成后面的运行时代码不能成功分配内存。
内存泄漏如何解决?方案一 引入gc,从语言层面解决内存泄漏;
方案二 当发生内存泄漏的时候,能够精准的定位代码那个文件、那个函数、哪一行所引起的。
我们实现的是方案二,核心需求有两个。
需求1: 能够检测出内存泄漏
需求2:能够指出是由代码的哪个文件、哪个函数、哪一行引起的内存泄漏
内存泄漏检测如何实现?内存泄漏检测实现的核心思想就是对系统的malloc/free进行hook,用我们自己的malloc/free代替系统调用,将free的地址和malloc的地址进行匹配,查看最后又哪些malloc没有进行free,并将没有free的malloc操作的代码段地址进行记录,通过代码段定位所在的文件、函数、代码行。
方案一采用__libc_malloc, libc_free与__builtin_return_address。它们是gcc提供的函数。
__libc_malloc, libc_free用来代替malloc/free。可以用来实现hook。需要注意的是,我们实现的malloc/free函数,内部会有一些函数如printf,fopen,需要防止它们会嵌套调用malloc/free。
__builtin_return_address,能够返回调用所在函数的代码段的地址。能够定位内存泄漏的具体位置。
malloc的时候,创建一个文件,文件名使用申请内存的地址,并记录申请该内存的代码段的地址;free的时候,删除对应的文件。
#include #include #include int enable_malloc_hook = 1;extern void *__libc_malloc(size_t size);int enable_free_hook = 1;extern void *__libc_free(void *p);void *malloc(size_t size) { if (enable_malloc_hook) { enable_malloc_hook = 0; void *p = __libc_malloc(size); void *caller = __builtin_return_address(0); char buff[128] = {0}; sprintf(buff, ./mem/%p.mem, p); file *fp = fopen(buff, w); fprintf(fp, [+%p]malloc -- > addr:%p size:%lun, caller, p, size); fflush(fp); enable_malloc_hook = 1; return p; } else { return __libc_malloc(size); } return null;}void free(void *p) { if (enable_free_hook) { enable_free_hook = 0; char buff[128] = {0}; sprintf(buff, ./mem/%p.mem, p); if (unlink(buff) addr:%p size:%lun, file, line, p, size); fflush(fp); fclose(fp); return p;}void free_hook(void *p, const char *file, int line) { char buff[128] = {0}; sprintf(buff, ./mem/%p.mem, p); if (unlink(buff) addr:%p size:%lun, caller, ptr, size); fflush(fp); fclose(fp); mem_trace(); return ptr;}void free_hook_f(void *p, const void *caller) { mem_untrace(); // printf(-%p: addr[%p]n, caller, p); char buff[128] = {0}; sprintf(buff, ./mem/%p.mem, p); if (unlink(buff) addr:%p size:%lun, caller, p, size); fflush(fp); enable_malloc_hook = 1; return p; } else { return malloc_f(size); } return null;}void free(void *p) { if (enable_free_hook) { enable_free_hook = 0; char buff[128] = {0}; sprintf(buff, ./mem/%p.mem, p); if (unlink(buff) < 0) { printf(double free: %pn, p); } free_f(p); enable_free_hook = 1; } else { free_f(p); }}static int init_hook() { malloc_f = dlsym(rtld_next, malloc); free_f = dlsym(rtld_next, free);}// gcc -o memleak_0 memleak_0.c -ldl -g// addr2line -f -e memleak_0 -a 0x4006d8int main() { init_hook(); void *p1 = malloc(10); void *p2 = malloc(20); free(p1); void *p3 = malloc(30); void *p4 = malloc(40); free(p2); free(p4); return 0;}
共享内存mmap方法1
匿名mmap
#include #include #include void *shm_mmap_alloc(int size) { void *addr = mmap(null, size, prot_read|prot_write, map_anon | map_shared, -1, 0); if (addr == map_failed) { return null; } return addr;}int shm_mmap_free(void *addr, int size) { return munmap(addr, size);}int main() { char *addr = (char *)shm_mmap_alloc(1024); pid_t pid = fork(); if (pid == 0) { // child int i = 0; while(i 0) { int i = 0; while (i++ < 26) { printf(parent: %sn, addr); sleep(1); } } shm_mmap_free(addr, 1024);}
mmap方法2
/dev/zero
#include #include #include #include #include #include void *shm_mmap_alloc(int size) { int fd = open(/dev/zero, o_rdwr); void *addr = mmap(null, size, prot_read|prot_write, map_shared, fd, 0); close(fd); if (addr == map_failed) { return null; } return addr;}int shm_mmap_free(void *addr, int size) { return munmap(addr, size);}int main() { char *addr = (char *)shm_mmap_alloc(1024); pid_t pid = fork(); if (pid == 0) { // child int i = 0; while(i 0) { int i = 0; while (i++ < 26) { printf(parent: %sn, addr); sleep(1); } } shm_mmap_free(addr, 1024);}shmget方法
#include #include #include #include #include #include #include #include void *shm_alloc(int size) { int segment_id = shmget(ipc_private, size, ipc_creat | ipc_excl | s_irusr | s_iwusr); char *addr = (char *)shmat(segment_id, null, 0); return addr;}int shm_free(void *addr) { return shmdt(addr);}int main() { char *addr = (char *)shm_alloc(1024); pid_t pid = fork(); if (pid == 0) { // child int i = 0; while(i 0) { int i = 0; while (i++ < 26) { printf(parent: %sn, addr); sleep(1); } } shm_free(addr);}
海尔凌越S4Plus评测 值不值得买
剑桥开发出一款可以帮助菜农剥掉生菜最外面烂叶子的机器人
打造武汉“氢能汽车之都” 预计2025年氢能电池年产值力争突破1000亿元
盘点设备、MO源等配套领域超百亿市值上市公司
使用万用表检查整个电路的连续性
内存泄漏会产生哪些后果
我国人工智能技术:泡沫正逐渐消逝 应用层占主导 仍缺高端人才
高通在台北电脑展上面正式发布骁龙850,专为搭载Windows 10 ARM系统的笔记本电脑打造的处理器
可靠的网络测量可改善QoE
数据波动的异常判别方法
!销售/维修/收购TDS784A示波器TDS 784A小兵/
负压救护车排风净化单元的研制与应用
到2025年,中东的物联网收入预计将超过15%的复合年增长率增长
选择交换机时应该从以下几方面去考虑
如何用BB Black制作DAC系统
手机home键都按不动了, 未来或将彻底消失
OPPO Reno3系列新品发布,首发QQ 5G 1080P高清视频通话
科学家发现可以解释机器人握住湿物体时发生摩擦的新物理定律
DNP双层背投屏幕技术及光学原理浅谈
itc云播系统改变“广播音质难突破”的行业现象