聊一聊內存泄漏 ------在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來檢測使用大量內存的程序就會遇到問題,它可能會用很長的 時間來運行測試


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM