聊一聊内存泄漏 ------在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;
}
View Code
复制代码

 

目前使用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;
}
View Code
复制代码

 

复制代码
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来检测使用大量内存的程序就会遇到问题,它可能会用很长的 时间来运行测试

posted @   codestacklinuxer  阅读(1473)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
历史上的今天:
2019-06-02 生活20190602
点击右上角即可分享
微信分享提示