在GCC C程序中获取内存信息

在GCC 中获取当前程序内存信息有几种手段
1 使用 mallinfo这个类
这部分code是直接抄来的,注意有很多项都是没用的,malloc 有两部分,一部分是使用sbrk申请的,不会还给系统,free过后会在total heap里,另一部分如果是大块内存申请的话会使用mmap
void getMemStatus()
{
    struct mallinfo info = mallinfo ();
    printf("arena = %d\n", info.arena);
    printf("ordblks = %d\n", info.ordblks);
    printf("smblks = %d\n", info.smblks);
    printf("hblks = %d\n", info.hblks);
    printf("hblkhd = %d\n", info.hblkhd);
    printf("usmblks = %d\n", info.usmblks);
    printf("fsmblks = %d\n", info.fsmblks);
    printf("uordblks = %d\n", info.uordblks);
    printf("fordblks = %d\n", info.fordblks);
    printf("keepcost = %d\n", info.keepcost);
}

Usage:


#include <malloc.h>

struct mallinfo [Data Type]
This structure type is used to return information about the dynamic memory allocator.
It contains the following members:
int arena
    This is the total size of memory allocated with sbrk by malloc, in bytes.
int ordblks
    This is the number of chunks not in use. (The memory allocator internally gets chunks of memory from the operating system, and then carves them up to satisfy individual malloc requests; see Section 3.2.2.6 [Eciency Considerations for malloc], page 36.)
int smblks
    This field is unused.
int hblks
    This is the total number of chunks allocated with mmap.
int hblkhd
    This is the total size of memory allocated with mmap, in bytes.
int usmblks
    This field is unused.
int fsmblks
    This field is unused.
int uordblks
    This is the total size of memory occupied by chunks handed out by malloc.
int fordblks
    This is the total size of memory occupied by free (not in use) chunks.
int keepcost
    This is the size of the top-most releasable chunk that normally borders the end of the heap (i.e., the high end of the virtual address space''s data segment).
struct mallinfo mallinfo (void) [Function]
    This function returns information about the current dynamic memory usage in a structure of type struct mallinfo.

2 使用mtrace
这个是GCC使用memory hook做的一个简单例子,在使用前需要设置环境变量MALLOC_TRACE,指向一个Log文件。check完后call muntrace或等待程序结束。
遗憾的是不能检查c++的,只看到了libstdc++.so
#include <stdio.h>
#include <error.h>
#include <mcheck.h>
int main(void){
    setenv("MALLOC_TRACE", "log", 1);   //设置环境变量MALLOC_TRACE
    mtrace();   //在需要检测的代码段之前调用mtrace函数
    char *str1 = (char*)malloc(10);
     char *str2 = (char*)malloc(10);
    free(str1);
    muntrace();    //在需要检测的代码段之后调用muntrace函数
    return 0;
}
跑完了使用gcc提供的perl写的工具mtrace来看,里面主要是使用了addr2line.
3 使用memory hook
如果有特殊要求,可以不用mtrace,直接用memory hook来干活,code还是copy过来的
主要是给几个全局函数指针赋值。下面的code有点啰嗦,不过不想改了,为了防止递归调用在自己的mhook里面要把malloc_hook恢复,其实只要置为null就行,malloc后置为自己的hook, 这个地方没有考虑多thread。
/* Prototypes for __malloc_hook, __free_hook */
#include <malloc.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 *);

     static void *(*old_malloc_hook) (size_t __size, __const __malloc_ptr_t);
     static void (*old_free_hook)  (void *__ptr, __const __malloc_ptr_t);
                   
/* Override initializing hook from the C library. */
void (*__malloc_initialize_hook) (void) = my_init_hook;

static void my_init_hook (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;
}
    
int    main ()
     {
         char *a=(char *)malloc(20);                         
         free(a);

   }

# ./handle

malloc (20) returns 0x804a008
freed pointer 0x804a008
4 使用backtrace 获取堆栈信息
gcc提供很方便的函数来干这活,windows就太麻烦了。
#include <execinfo.h>
static void test2()
{
int i = 0;
void* buffer[MAX_LEVEL] = {0};

int size = backtrace(buffer, MAX_LEVEL);

for(i = 0; i < size; i++)
{
  printf("called by %p\n", buffer[i]);
}

return;
}
跑完之后大家不知道有什么想法没
5 使用memory hook + backtrace获取C++ 对象创建信息
这个是重点:)
据我推测,没有去check gcc malloc() code确认,其实mhook就是把调用的地址传给hook函数而已,那么c++的new 其实可以跟踪出来的,就在mhook里加上backtrace就行
代码就不贴了,把上面的组合一下就可以。已经实验确认过, 想知道c++是否内存泄露可以用这个来check,如果不想用其他大型工具的话。

注意编译时要打开debug信息,否则得不到具体地址。如果是非debug版可以使用编译生成的map文件进行大致定位。
由memory hook推广开来,如果在其他资源比如pthread的一些操作里增加backtrace的check我们可以获取详细的线程,锁信息,获取这个干嘛就不用说了吧。可惜pthread没有hook,只能自己做wraper了。

一个想法,既然gcc已经提供了这么丰富的工具,其实我们可以把这些信息存下来或者发送出去,可以得知程序的详细信息,然后用工具分析 就像java profiler那样,检查资源分配的粒度频度,是否死锁等等


你可能感兴趣的:(C++,c,C#,gcc,perl)