• 嵌入式系统内存泄漏检测


    很多人喜欢抱怨,嵌入式系统什么调试工具都没提供。这是事实,嵌入式操作系统,除了vxWorks还算强大外,其它系统能提供的东西真的少的可怜。哥倒是挺喜欢这样,时不时做点小工具,调节下神经,算是个开心的事。内存泄漏的检测就是蛮好玩的,原理简单,应用简单,且容易看到成果。

    内存泄漏,就是忘记释放之前分配的堆内存,malloc, realloc少做了free操作。内存泄漏工具的基本原理就是捕获每一次malloc,realloc和free操作,在分配时将分配信息保存在一个列表里,释放时再从列表里清除。工具在设计的关键在于如何设计这个表,做到能够适应大量分配、释放操作的非常高效的频繁更新。当然,这些操作本身还不能调用外部(本C文件外)一个内嵌了mallc,free的操作,比如printf就应该避免,否则会形成递归错误。

    还有一点需要提前说明的,内存是不是泄漏,软件本身并不能确认的,要靠人工根据实际代码功能进行分析。工具只能提供一个谁的嫌疑最大,让分析者能更快的发现并找到问题。

    至于高效的存取列表,可以用zlib里的hash和avl。它们的实例是提前配置的,不存在动态分配内存问题。当然,自己搞一个也不错,列表是高效的就行。

    http://files.cnblogs.com/files/hhao020/cshell_prj_with_memleak_util.rar
    链接包含zlib,memleak等,下载软件包,解压后在linux下编译。

    要让程序附加内存泄漏检测功能,需要在公共头文件里重定义malloc,realloc和free操作,如下:

    #define malloc(size) tml_malloc(size, __FUNCTION__, __LINE__)
    #define realloc(mem, size) tml_malloc(mem, size, __FUNCTION__, __LINE__)
    #define free(mem) tml_free(mem)
    IMPORT void* tml_malloc(int size, const char* function, int line);
    IMPORT void tml_free(void* mem);
    IMPORT void* tml_realloc(void* mem, int size, const char* function, int line);

    在我提供的代码中,这个是加入到zType_Def.h中的,因为我的代码里,只有zType_Def.h是应用必须引用的。当然,如果有不引用的,memory leak检测是没办法的。

    这段程序,先把malloc等函数编程宏操作。因为编译器总是先做预编译,这个阶段是不管看到的东西是函数还是变量,只要字符串跟宏定义相同,就会被替换。等预编译完成,所有代码里就只有tml_malloc,而没malloc调用了;当然,memleak.c除外,它里面还是要调用真实的malloc,free的。

    memleak.c实现如下:

    /*----------------------------------------------------------
    File Name  : xxx.c
    Description: 
    Author     : hhao020@gmail.com (bug fixing and consulting)
    Date       : 2007-05-15
    ------------------------------------------------------------*/  
    #include "zType_Def.h"
    
    #ifdef malloc
    #undef malloc
    #endif
    
    #ifdef free
    #undef free
    #endif
    
    #ifdef realloc
    #undef realloc
    #endif
    
    
    /** copy below lines to a common header file
    
    #define malloc(size) tml_malloc(size, __FUNCTION__, __LINE__)
    #define realloc(mem, size) tml_malloc(mem, size, __FUNCTION__, __LINE__)
    #define free(mem)      tml_free(mem)
    IMPORT void* tml_malloc(int size, const char* function, int line);
    IMPORT void  tml_free(void* mem);
    IMPORT void* tml_realloc(void* mem, int size, const char* function, int line);
    
    ** copy ends*/
    
    //#include "zTraceApi.h"   //replace zlib with stdlib, to make the tool be lighter
    //#include "zSalOS.h"
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    #include "memleak.h"
    
    typedef struct MEMORY_LEAK_TYPE
    {
      void* mem;
      int   size;
      const char* function;
      int   line;
      int   tAlloc;
    } MemLeak_t;
    
    static MemLeak_t g_memleaks[128] = { {0,}, };
    
    
    
    static int tml_insert(void* mem, int size, const char* function, int line)
    {
      int i;
      for(i=0; i<TBL_SIZE(g_memleaks); i++)
      {
        if(g_memleaks[i].mem) continue;
        g_memleaks[i].mem = mem;
        g_memleaks[i].size = size;
        g_memleaks[i].function = function;
        g_memleaks[i].line = line;
        g_memleaks[i].tAlloc = time(0); //zTime(0);
    
        return 1;
      }
    
      return 0;
    }
    
    static int tml_remove(void* mem)
    {
      int i;
      for(i=0; i<TBL_SIZE(g_memleaks); i++)
      {
        if(g_memleaks[i].mem != mem) continue;
        g_memleaks[i].mem = 0;
    
        return 1;
      }
      
      return 0;
    }
    
    void* tml_realloc(void* mem, int size, const char* function, int line)
    {
      if(mem) //note, a null memory must cause exception and crash
      {
        tml_remove(mem);
      }
    
      mem = realloc(mem, size);
    
      if(mem)
      {
        tml_insert(mem, size, function, line);
      }
    
      return mem;
    }
    
    void* tml_malloc(int size, const char* function, int line)
    {
      void *mem = malloc(size);
      
      if(mem) tml_insert(mem, size, function, line);
      
      return mem;
    }
    
    void  tml_free(void* mem)
    {
      if(mem) //note, a null memory must cause exception and crash
      {
        tml_remove(mem);
      }
    
      free(mem);
    
      return;
    }
    
    int tml_cleanall()
    {
      memset(&g_memleaks[0], 0, sizeof(g_memleaks));
      return 0;
    }
    
    int tml_show(int ref_seconds) //only those memory allocated before ref_seconds are leak candidates
    {
      int now = time(0);
      
      int i;
      for(i=0; i<TBL_SIZE(g_memleaks); i++)
      {
        if(!g_memleaks[i].mem) continue;
        if(now - g_memleaks[i].tAlloc <= ref_seconds) continue;
    
        printf("mem: %p size: %6d  @%s:%d  tAlloc: -%d
    ", g_memleaks[i].mem, g_memleaks[i].size, g_memleaks[i].function, g_memleaks[i].line, now-g_memleaks[i].tAlloc);
      }
      return 1;
    }
    View Code

    看,undef又将刚才的宏全部去掉了,这时候看到的malloc和free,就是真实的系统内存操作函数。这里必须要注意,如果刚刚的宏定义所在文件被引用,则必须放在undef前。否则undef就不生效了。

    再接着,就是tml_malloc等函数的实现。我给的例子,用了个简单的数组,只是抛砖引玉,实际不可以这样,因为malloc这类操作可能很频繁(否则也就不会内存泄漏了)。如此低效的插入删除,系统早累趴下了!


    当然,哥写的程序,几乎不在运行期调用任何malloc或是free;内存泄漏检测这玩意,就是给一般项目用的。

    哦,差点忘记了,光记下当前函数是不够的,还应该从当前TCB获取task信息和栈顶附近的几个调用,不会的话,翻前一篇系统挂起检测文章。这样就能找到准确的谁调用的,在做什么。Linux下做这个有点困难,嵌入式软件就很容易做到。不过也没啥,有了一个调用者信息,还有相对应的内存也可以dump出来分析,基本上问题都能解决了。

    测试示例:

    cshell_prj $ bin/target_a.linux.i32.exe 
    ->p=0
    
    $1/> p=0
    
     = 0 (0x0) <:0x3d :61 :'=' : size=0>
    ->p=testMalloc(100)
    
    $2/> p=testMalloc(100)
    
     = 150846704 (0x8FDBCF0) <:0x3d :61 :'=' : size=0>
    ->tml_show()
    
    $3/> tml_show()
    
    mem: 0x8fdbcf0 size:    100  @testMalloc:35  tAlloc: -4
     = 1 (0x1) <FUNCALL : size=0>
    ->testFree(p)
    
    $4/> testFree(p)
    
     = 115480  (0x1C318) <FUNCALL : size=4>
    ->tml_show()
    
    $5/> tml_show()
    
     = 1 (0x1) <FUNCALL : size=0>
    ->
  • 相关阅读:
    第一节:理解垃圾回收平台的基本工作原理
    回想笔记 瞎比比 域名注册 解析绑定ip 下载证书 设置证书 重定向http到https请求
    flask 设置https请求 访问flask服务器
    关于 服务器ip和域名进行一个绑定
    ubuntu 安装flask+nginx+gunicorn 待定
    使用flask-dropzone 上传图片文件
    flask 对于用户登录保持状态 flask_login
    flask 对于邮件url进行一个加密防止爆破
    flask 密码加密 视频资料
    flask 多线程邮件异步发送 视频资料
  • 原文地址:https://www.cnblogs.com/hhao020/p/5016978.html
Copyright © 2020-2023  润新知