admin管理员组

文章数量:1531732

用valgrind检测内存泄露的时候,发现一个问题,就是程序总会报一个泄露点

1 blocks are still reachable

查了程序发现并没有泄露,最后百度才知道我对内存泄露的知识理解并不全面

以前我的理解是,只要分配的内存但是没释放就会导致内存泄露

但是这养理解是不全面的。只要分配了内存,如果它的指针没有丢失,那么就不算是泄露

所以来说,static的指针或者全局指针,如果没有释放它,那也算是not-freed blocks,也就是reachable的,但是现代的OS会得到这些指针并去释放它

下面内容摘抄于https://bbs.csdn/topics/60443491 @天笑2001

  1. 使用全局指针或静态指针:
int main()
{
    static int  *pi; // use static pointer: not a real memory leak!!!      
    pi = new int;
    return 0;
}

使用valgrind检查:

 valgrind --leak-check=yes --show-reachable=yes -q ./memtest  
==13782== searching for pointers to 1 not-freed blocks. 
==13782== checked 4484352 bytes. 
==13782== 
==13782== 4 bytes in 1 blocks are definitely lost in loss record 1 of 1 
==13782==    at 0xB74D27AB: __builtin_new (vg_replace_malloc.c:172) 
==13782==    by 0xB74D2802: operator new(unsigned) (vg_replace_malloc.c:185) 
==13782==    by 0x8048491: main (in /home/prog/valgrind/memtest) 
==13782==    by 0xB71C4BA6: __libc_start_main (in /lib/libc-2.3.2.so) 
==13782== 
==13782== LEAK SUMMARY: 
==13782==    definitely lost: 4 bytes in 1 blocks. 
==13782==    possibly lost:   0 bytes in 0 blocks. 
==13782==    still reachable: 0 bytes in 0 blocks. 
==13782==         suppressed: 0 bytes in 0 blocks. 
==13782==

报告说有一个"not-freed block",但这个block是reachable的,所以它不算是真正的memory leak.

  1. 如果使用的是局部指针:
int main()
{
    int *pi; // use local pointer: real memory leak!!!    
    pi = new int[100];
    return 0;
}
==13782== searching for pointers to 1 not-freed blocks. 
==13782== checked 4484352 bytes. 
==13782== 
==13782== 4 bytes in 1 blocks are definitely lost in loss record 1 of 1 
==13782==    at 0xB74D27AB: __builtin_new (vg_replace_malloc.c:172) 
==13782==    by 0xB74D2802: operator new(unsigned) (vg_replace_malloc.c:185) 
==13782==    by 0x8048491: main (in /home/prog/valgrind/memtest) 
==13782==    by 0xB71C4BA6: __libc_start_main (in /lib/libc-2.3.2.so) 
==13782== 
==13782== LEAK SUMMARY: 
==13782==    definitely lost: 4 bytes in 1 blocks. 
==13782==    possibly lost:   0 bytes in 0 blocks. 
==13782==    still reachable: 0 bytes in 0 blocks. 
==13782==         suppressed: 0 bytes in 0 blocks. 
==13782==

报告说是"definitely lost",这才是真正的memory leak!

2 当然,我们一般情况下是不会分配内存而不释放的. 它的典型应用便是著名的memory pool . 其要领是为了提高内存管理的效率,针对特殊需要(如要分配的内存是等大的并且很小)去重载new,delete操作符. 它会避免每次申请很小的内存,而是一下子得到很大的一块,再自己去定义和使用.(出于效率的考虑,它最后并不释放) 我花了一下午时间分析的我用的SGI STL的内存分配源码(我是在LINUX下使用g++的), 下面一段是在/usr/include/c++/3.2.3/bits/stl_alloc.h中找到的STL源码:

template <bool __threads, int __inst>     class __default_alloc_template     
{
  private:
    enum {_ALIGN = 8};
    enum {_MAX_BYTES = 128};
    enum {_NFREELISTS = _MAX_BYTES / _ALIGN};
    union _Obj
    {
        union _Obj * _M_free_list_link;
        char _M_client_data[1]; // The client sees this.    
           
    };
    static _Obj
        * volatile _S_free_list[_NFREELISTS]; // Chunk allocation state.      
    static char * _S_start_free;
    static size_t _S_heap_size;
    static _STL_mutex_lock _S_node_allocator_lock;
    ....
}

可以看到,在关键的数据结构上,它使用了静态的指针,并且定义了一些常量来控制内存块的大小等.

3 对于这种技术是不是"隐式的内存泄漏" , 我认为不是. 隐式的内存泄漏指分配内存后,虽然也释放,但没有及时释放,导致内存消耗无法及时回收.在服务器编程时特别忌讳. 一般说来, 内存池的大小是可控, 不会一直增长下去. 从应用的层面上来说,它也是"释放"了内存了的.

本文标签: 内存valgrind