您的位置:首页 > 其它

一个简单的可移植 模块/系统动态内存 跟踪方法

2010-08-09 15:25 495 查看
一个简单的可移植
模块/系统动态内存
跟踪方法


在嵌入式系统或一些内存申请,释放频繁的场合,很难统计当前使用的动态内存,和整个软件模块运行过程中的内存使用的峰值;或者模块卸载时内存有无完全释放,还有就是动态内存的踩踏检查。针对这种需求,本文给出一种
简单的解决办法,并用 c code
描述出来。


感性认识

本文命名所建立的跟踪模块为mtrace

mtrace可以用来
跟踪当前
系统/模块的内存
使用情况
,以及估算系统/模块的占用内存的极值

系统/模块
卸载时的
内存
泄露情况。

模块内存跟踪只在
dbg模式下有效
,rom
下自动
变成mode 0
模块内存跟踪
有 0,1,2,3
四种模式
,其中 mode 0,3
没有内存使用统计;mode 1,2有内存使用统计,具体说明如下。


Mode
总开关

FS_TRACE_MEM 控制

FS_TRACE_MEM =0
,(mode 0)
其上所有
系统/模块
不使用内存跟踪

FS_TRACE_MEM =1
,(mode 1)其上所有
系统/模块使用内存跟踪,只统计
系统/模块
占用总量大小,具体在各系统/模块
声明的TRACE_MEMSTAT
中,如fat
为fat_memstat,ntfs
为ntfs_memstat,hfs+为hfsplus_memstat
;default_memstat
为其上所有
系统/模块
内存跟踪统计,如下图



说明:

int calloc; 当前模块调用
calloc申请
的字节数

int malloc; 当前模块调用 malloc申请
的字节数

int realloc; 当前模块调用 realloc申请
的字节数

int total; 当前模块迄今
申请内存
的总字节数 (以上3项总和)

int max_once; 模块迄今
一次申请
最多字节数

int max_total; 模块迄今
使用最多情况下的
总字节数,即峰值


int calloc_cnt; 模块
调用
有效calloc的次数

int malloc_cnt; 模块
调用
有效malloc的次数

int realloc_cnt; 模块
调用
有效realloc的次数

int total_cnt; 模块
申请内存
的总次数 (以上3项总和)

int max_total_cnt; 模块迄今
申请内存
的总次数最大值

FS_TRACE_MEM =2
,(mode 2)其上所有
系统/模块
使用内存跟踪,包括统计占用总量大小,内存分配日志
,具体在各
系统/模块
声明的TRACE_MEMSTAT

;而且日志
极限数目
由每个系统/模块
的MAX_ALLOC_ENTRYS

控制
。如fat为fat_memstat,ntfs
为ntfs_memstat,hfs+为hfsplus_memstat
;default_memstat
为其上所有
系统/模块
内存跟踪统计,跟踪日志在memstat结构的 log结构中,如下图



说明:

int calloc;

int malloc;

int total;
int realloc;

int max_once;

int max_total;


int calloc_cnt;

int malloc_cnt;

int realloc_cnt;

int total_cnt;

int max_total_cnt; 同上


int flag; //日志系内部标志

u16 limit; //系统/模块最多可容纳
日志数 ,与MAX_ALLOC_ENTRYS有关

s16 max_index; //最后一个
占用日志
索引

u16 free_index; //第一个
空闲日志
索引

u16 alloc_count; //迄今
已使用
日志数

u16 max_alloc_count; //迄今
使用最多日志情况下的
日志数

char *logstr[MAX_ALLOC_ENTRYS]; //日志数组


如果内存申请成功 ,写入有效日志,
第三个逗号后为
申请内存处
所在文件的
文件名字符串;
第二个逗号后为
申请内存处
该文件的所在行数;
第一个逗号后为在该处
申请的总有效字节数;第一个逗号内为在该处
申请的总有效次数,
如果
该文件
对应 line
的申请
内存被全部释放 ,
该处日志 = 0,如上图13,15,16


如果
系统/模块退出,
所有内存释放 ,如下图,可以用来跟踪
系统/模块
内存的泄漏情况





从上图可以看看出
,系统在任何调试时刻
,可以看到模块占用的内存统计和申请情况。大大方便
用户对
模块使用内存的评估



如何使用:
举例如下:假设要评估的模块是 hfs



(1)在
评估
模块或系统的
*.h或*.c
文件内,
加入
#define
TRACE_MEMSTAT & hfs_memstat
//
指定跟踪模块命名
#define MAX_ALLOC_ENTRYS
128 //仅FS_TRACE_MEM =2有用
#include "mtarce.h"

DECLARE_MEMSTAT(hfs_memstat);

#define hfs_calloc( size)
mtrace_calloc(size)
#define hfs_malloc( size)
mtrace_malloc(size )
#define hfs_realloc(p, size)
mtrace_realloc( p ,size )
#define hfs_free(p)
mtrace_free(p)

确保每个c文件
都会编译到

(2)某一c文件
加入
DEFINE_MEMSTAT ((hfs_memstat);
//仅需一次

(3)系统项目编译链接
加入 mtrace.c
文件

(4)以后在模块(或系统)凡是使用
内存分配例程的地方
都替换为 mtrace_XXX或 hfs_XXX对应例程。

通过以上几步,即可应用mtrace
的动态
内存使用情况
跟踪

源码说明:
mtrace
由2个可移植文件组成mtrace.h, mtrace.c
其中mtrace.h
为算法配置和声明,mtrace.c为算法实现,详细列举如下


mtrace.h


#ifndef MTRACE_H
#define MTRACE_H

////////////configurations ////////////////////

#include "includes.h"

#ifndef __ROM_


#define FS_PRINT_ENABLE 1

#define FS_TRACE_MEM 2
//0,1,2,3 可以修改
#else
//dont modify below

#define FS_PRINT_ENABLE 0


#define FS_TRACE_MEM 0

#endif

//fit to yourown requirement
#define
u16 unsigned short
#define
s16 signed short
//#define
size_t int

#define raw_calloc( n , size)
calloc(n ,size)
#define raw_malloc( size)
malloc(size)
#define raw_realloc(p, size)
realloc( p ,size )
#define raw_free(p)
free( p )

#define DECLEAR_KEY(x)
OS_EVENT *x=NULL
#define INIT_THREAD_MUTEX()
***SemCreate(1)
#define THREAD_LOCK(x) {INT8U
err; ***SemPend(x,0,&err); }
#define THREAD_UNLOCK(x) ***SemPost(x)

////////////////////////////////////////////////

#ifndef ENOMEM

#define ENOMEM 12
#endif

#if( FS_TRACE_MEM>2)

#define mtrace_calloc(n, size)
raw_calloc(n,size)
#define mtrace_malloc( size)
raw_malloc(size)
#define mtrace_realloc(p, size)
raw_realloc( p ,size )
#define mtrace_free(p)
raw_free( p )

#define
DEFINE_MEMSTAT(stat) //
#define
DECLARE_MEMSTAT(stat) //


#elif( FS_TRACE_MEM>0)

#ifndef MAX_ALLOC_ENTRYS


#define MAX_ALLOC_ENTRYS 128
#endif


#define memstat_log_inited
0x01
#define memstat_log_allused
0x02

#define memstat_log_index_invalid
-1

typedef struct

{

int calloc;

int malloc;

int realloc;

int total;



int max_once;

int max_total;


int calloc_cnt;

int malloc_cnt;

int realloc_cnt;

int total_cnt;

int max_total_cnt;


struct

{

int flag;

u16 limit;
#if( FS_TRACE_MEM&2)

s16 max_index; //max valid index,fast find
matched log

u16 free_index; //first free log index,fast for next log if all exist not matched

u16 alloc_count; //current total used log entrys

u16 max_alloc_count;

char *logstr[MAX_ALLOC_ENTRYS];
//
char **logstr;
#endif

}log;
}memstat;

#define
DEFINE_MEMSTAT(hinst) memstat hinst={0,0,0,0,0, 0,0,0,0,0,0,{0,MAX_ALLOC_ENTRYS}}
#define
DECLARE_MEMSTAT(hinst) extern
memstat hinst

void *mtrace_calloc_trace(size_t size,int line, char *file,memstat *stat);
void *mtrace_malloc_trace(size_t size,int line, char *file,memstat *stat);
void *mtrace_realloc_trace(void *old,size_t size,int line, char *file,memstat *stat);
void mtrace_free_trace (void *pmen,memstat *stat);


DECLARE_MEMSTAT(default_memstat);

#ifndef TRACE_MEMSTAT

#define TRACE_MEMSTAT &default_memstat
#endif

#define mtrace_calloc( size)
mtrace_calloc_trace(size, __LINE__, __FILE__,TRACE_MEMSTAT)
#define mtrace_malloc( size)
mtrace_malloc_trace(size ,__LINE__, __FILE__,TRACE_MEMSTAT)
#define mtrace_realloc(p, size) mtrace_realloc_trace( p ,size ,__LINE__, __FILE__,TRACE_MEMSTAT)
#define mtrace_free(p)
mtrace_free_trace( p , TRACE_MEMSTAT)


#else

#define
DEFINE_MEMSTAT(stat) //
#define
DECLARE_MEMSTAT(stat) //

void *mtrace_calloc(size_t size);
void *mtrace_malloc(size_t size);
void *mtrace_realloc(void *old,size_t size);
void mtrace_free(void pmen);

#endif

#if FS_PRINT_ENABLE

void mtrace_log_redirect(const char *function, const char *file, int line,

const char *FORMAT, ...);
#define mtrace_log_error(arg...)
mtrace_log_redirect(__FUNCTION__,__FILE__,__LINE__,arg)

#else

#define mtrace_log_error(arg...)
//

#endif


#endif


mtarce.c

#include " mtarce.h"

#if( FS_TRACE_MEM>2)

#elif( FS_TRACE_MEM>0)
#define
MH_MAGIC_MASK 0xFFFFFFFC
#define
MH_TYPE_MASK 0x00000003

#define
MH_MAGIC_ALLOC 0xCCCCCCCC
#define
MH_MAGIC_FREE 0xEEEEEEEE
#define
MH_TYPE_C 0
#define
MH_TYPE_M 1
#define
MH_TYPE_R 2

typedef struct
{
int magic;
//0xcccc , low nibble for type
int size;

#if( FS_TRACE_MEM&2)
int logindex;
#endif

}meminfo;

#define
meminfo_len sizeof(meminfo)

DEFINE_MEMSTAT(default_memstat);
//total mem trace for all fs

#if( FS_TRACE_MEM&2)

#define MAX_ALLOC_FILNAMELEN 32
#define MEMLOG_STATEFREE
0

#define thisfs_memlog
stat->log

static void init_memlog(memstat *stat)
{
if(thisfs_memlog.flag&memstat_log_inited)

return ;

#if 0
char *log =(char *) calloc(sizeof(char *),thisfs_memlog.limit);
if (!log)
{

fs_log_error("Failed to calloc %d logs/n", (long)thisfs_memlog.limit);

return ;
}

thisfs_memlog.logstr = (char **)log;
#endif

for (int i=0;i<thisfs_memlog.limit;i++)
{

thisfs_memlog.logstr[i]=MEMLOG_STATEFREE;
}
thisfs_memlog.max_index=-1;
thisfs_memlog.free_index=0;
thisfs_memlog.alloc_count=0;
thisfs_memlog.flag |= memstat_log_inited;

if(default_memstat.log.flag&memstat_log_inited)

return ;

// default_memstat.log.limit = MAX_ALLOC_ENTRYS;
#if 0
log =(char *) calloc(sizeof(char *),default_memstat.log.limit);
if (!log)
{

fs_log_error("Failed to calloc %d logs/n", (long)default_memstat.log.limit);

return ;
}

thisfs_memlog.logstr = (char **)log;
#endif

for ( i=0;i < default_memstat.log.limit;i++)
{

default_memstat.log.logstr[i]=MEMLOG_STATEFREE;
}

default_memstat.log.max_index=-1;
default_memstat.log.free_index=0;
default_memstat.log.alloc_count=0;
default_memstat.log.flag |= memstat_log_inited;

}


#define logfmt "%d,%d,%d,%s"
static size_t o_size;
static char o_file[MAX_ALLOC_FILNAMELEN];
static int o_line;
static int o_times;

static int register_log(meminfo *p,int line, char *file,memstat *stat)
{

int i,j;
int
retry=0;
size_t size
= p ->size;

init_memlog(stat);

p->logindex = memstat_log_index_invalid;

//use the already log entry

for( i=0 ;i<=thisfs_memlog.max_index;i++)
{


if(thisfs_memlog.logstr[i]==MEMLOG_STATEFREE)

continue;



sscanf(thisfs_memlog.logstr[i], logfmt,
&o_times,&o_size,&o_line, o_file);

if(/*(o_size==size)&&*/(o_line==line)&&(strcmp(o_file,file)==0)&&o_times>0)

{

snprintf((char*) thisfs_memlog.logstr[i] ,MAX_ALLOC_FILNAMELEN, logfmt ,o_times+1,size+o_size,line,file);

p->logindex = i;

return 0;

}
}


//create new log
if(thisfs_memlog.flag & memstat_log_allused)
{

fs_log_info("all used out now/n");

return -1;
}

j=thisfs_memlog.free_index;

if(thisfs_memlog.logstr[j])
{

fs_log_error("already used now/n");

for(i = 0 ;i<thisfs_memlog.limit;i++)

{

if(thisfs_memlog.logstr[i]==MEMLOG_STATEFREE)

break;

}

if(i==thisfs_memlog.limit)

{

thisfs_memlog.flag|=memstat_log_allused;

fs_log_error("all used out now/n");

return -1;

}

j = i;
}

thisfs_memlog.logstr[j] =(char *)
malloc(MAX_ALLOC_FILNAMELEN);
if (!thisfs_memlog.logstr[j])
{

fs_log_error("Failed to malloc %d bytes/n", (long)size);

thisfs_memlog.free_index = i;

return -1;
}
snprintf((char*) thisfs_memlog.logstr[j] ,MAX_ALLOC_FILNAMELEN, logfmt, 1,size,line,file);
thisfs_memlog.alloc_count++;

if(thisfs_memlog.max_alloc_count<thisfs_memlog.alloc_count)

thisfs_memlog.max_alloc_count=thisfs_memlog.alloc_count;

if(thisfs_memlog.max_index< j)

thisfs_memlog.max_index=j;

i = j+1 ;

again:

if(thisfs_memlog.alloc_count<thisfs_memlog.limit)
//find free log entry
{

for( ;i<thisfs_memlog.limit;i++)

{

if(thisfs_memlog.logstr[i]==MEMLOG_STATEFREE)

break;

}

if(i==thisfs_memlog.limit )

{

if(!retry)

{

i = 0 ;

retry = 1;

goto again;

}

thisfs_memlog.flag|=memstat_log_allused;

}

else

{

thisfs_memlog.free_index = i;

}
}
else
{

thisfs_memlog.flag |= memstat_log_allused;
}
p->logindex = j;
return
0;
}

static void unregister_log(meminfo *p,memstat *stat)
{
int j = p->logindex;


if(j<0||j>thisfs_memlog.limit)

return ;

if(thisfs_memlog.logstr[j]==MEMLOG_STATEFREE)
{

fs_log_error("already free /n");

return ;
}

sscanf(thisfs_memlog.logstr[j],
logfmt, &o_times,&o_size,&o_line, o_file);
if(o_times>1)
{

snprintf((char*) thisfs_memlog.logstr[j] ,MAX_ALLOC_FILNAMELEN, logfmt ,--o_times,o_size-p->size,o_line,o_file);

return ;
}


free(thisfs_memlog.logstr[j]);
thisfs_memlog.logstr[j]=MEMLOG_STATEFREE;
if((thisfs_memlog.flag & memstat_log_allused) || (thisfs_memlog.free_index> j))

thisfs_memlog.free_index =j;
thisfs_memlog.alloc_count--;

if(thisfs_memlog.max_index== j)
{

for( ;j>=0&&thisfs_memlog.logstr[j]==MEMLOG_STATEFREE;j--)

thisfs_memlog.max_index--;
}

thisfs_memlog.flag &=~memstat_log_allused;

}


#endif

static OS_EVENT
*memstat_sem=NULL; // perhaps
this module will run on multiple task
static int
updata_meminfo(meminfo *p,int type,int size ,memstat *stat ,int line, char *file)
{
int ret =0;

if(!memstat_sem)

{

memstat_sem = ***SemCreate (1);

if(!memstat_sem)

{

fs_log_error("memstat_sem create fail/n", p);

return -1;

}
}

***SemPend(memstat_sem,0,(INT8U *) &ret);
if(size>0)
{

p->magic=MH_MAGIC_ALLOC|type;

p->size=size;


if(type==MH_TYPE_C)

{

stat->calloc+=size;

stat->calloc_cnt++;

}

else if(type==MH_TYPE_M)

{

stat->malloc +=size ;

stat->malloc_cnt++;

}

else

{

stat->realloc+=size;

stat->realloc_cnt++;

}



stat->total+=size;

stat->total_cnt++;



if(stat->max_once<size)

stat->max_once=size;

if(stat->max_total<stat->total)

stat->max_total=stat->total;

if(stat->max_total_cnt<stat->total_cnt)

stat->max_total_cnt=stat->total_cnt;


if(stat!= &default_memstat)

{

if(type==MH_TYPE_C)

{

default_memstat.calloc+=size;

default_memstat.calloc_cnt++;

}

else if(type==MH_TYPE_M)

{

default_memstat.malloc +=size ;

default_memstat.malloc_cnt++;

}

else

{

default_memstat.realloc+=size;

default_memstat.realloc_cnt++;

}



default_memstat.total+=size;

default_memstat.total_cnt++;



if(default_memstat.max_once<size)

default_memstat.max_once=size;

if(default_memstat.max_total<default_memstat.total)

default_memstat.max_total=default_memstat.total;



if(default_memstat.max_total_cnt<default_memstat.total_cnt)

default_memstat.max_total_cnt=default_memstat.total_cnt;

}


#if( FS_TRACE_MEM&2)

ret = register_log(p,line,file,stat);
#endif


}
else
{


type = p->magic&MH_TYPE_MASK;

if(p->magic==MH_MAGIC_FREE)

{

fs_log_error("free 0x%x again/n", p);

***SemPost(memstat_sem);

return -1;

}

if((p->magic&MH_MAGIC_MASK)!=MH_MAGIC_ALLOC||type>MH_TYPE_R||type<MH_TYPE_C)

{

fs_log_error("free 0x%x mismatch/n", p);

***SemPost(memstat_sem);

return -1;

}

p->magic=MH_MAGIC_FREE; //avoid
free again



size=p->size;

if(type==MH_TYPE_C)

{

stat->calloc -=size ;

stat->calloc_cnt--;

}

else if(type==MH_TYPE_M)

{

stat->malloc -=size ;

stat->malloc_cnt--;

}

else

{

stat->realloc -=size ;

stat->realloc_cnt--;

}

stat->total-=size ;

stat->total_cnt--;


if(stat!= &default_memstat)

{

if(type==MH_TYPE_C)

{

default_memstat.calloc -=size ;

default_memstat.calloc_cnt--;

}

else if(type==MH_TYPE_M)

{

default_memstat.malloc -=size ;

default_memstat.malloc_cnt--;

}

else

{

default_memstat.realloc -=size ;

default_memstat.realloc_cnt--;

}

default_memstat.total-=size ;

default_memstat.total_cnt--;

}


#if( FS_TRACE_MEM&2)

unregister_log(p,stat);
#endif

}

***SemPost(memstat_sem);

return ret;
}

/**
* ntmtrace_calloc
*
* Return a pointer to the allocated memory or NULL if the request fails.
*/
void *mtrace_calloc_trace(size_t size,int line, char *file,memstat *stat)
{

meminfo *p;

if(size<=0)
return NULL;

p =(meminfo *) calloc(1,size+meminfo_len);
if (!p)
{

fs_log_error("Failed to calloc %d bytes/n", (long)size);

errno = ENOMEM;

return NULL;
}

updata_meminfo(p, MH_TYPE_C,size,stat,line,file);

return (char *)p+meminfo_len;
}


void *mtrace_malloc_trace(size_t size,int line, char *file,memstat *stat)
{

meminfo *p;

if(size<=0)
return NULL;

p =(meminfo *)
malloc(size+meminfo_len);
if (!p)
{

fs_log_error("Failed to malloc %d bytes/n", (long)size);


errno = ENOMEM;

return NULL;
}

updata_meminfo(p, MH_TYPE_M,size,stat,line,file);

return (char *)p+meminfo_len;
}


void *mtrace_realloc_trace(void *old,size_t size,int line, char *file,memstat *stat)
{

meminfo *p;
int type ;

if(size<=0)
return NULL;

if(old)
{

p =(meminfo *) ((char *)old -meminfo_len) ;



if(updata_meminfo(p, -1,-1,stat , -1 ,NULL)!=0)

{

return NULL;

}

type = MH_TYPE_R ;
}
else
{

p = NULL;

type = MH_TYPE_M ;
}
p =(meminfo *)
realloc(p,size+meminfo_len);
if (!p)
{

fs_log_error("Failed to realloc %d bytes/n", (long)size);

errno = ENOMEM;

return NULL;
}

updata_meminfo(p, type,size,stat,line,file);

return (char *)p+meminfo_len;
}

void mtrace_free_trace(void *pmen,memstat *stat)
{

if(pmen)
{

meminfo *p =(meminfo *) ((char *)pmen -meminfo_len) ;



if(updata_meminfo(p, -1,-1,stat, -1,NULL)==0)

{

free(p);

}
}
}

#else


void *mtrace_calloc(size_t size)
{

void *p;

if(size<=0)
return NULL;

p = calloc(1,size);
if (!p)
{

fs_log_error("Failed to calloc %d bytes/n", (long)size);

errno = ENOMEM;
}

return p;
}


void *mtrace_malloc(size_t size)
{
void *p;

if(size<=0)
return NULL;

p = malloc(size);
if (!p)
{

fs_log_error("Failed to malloc %d bytes/n", (long)size);

errno = ENOMEM;
}

return p;
}


void *mtrace_realloc(void *old,size_t size)
{

void *p;

if(size<=0)
return NULL;

p = realloc(old,size);
if (!p)
{

fs_log_error("Failed to realloc %d bytes/n", (long)size);

errno = ENOMEM;
}

return p;
}

void mtrace_free(void *pmen)
{
if(pmen)
{

free(pmen);
}
}
#endif

#if FS_PRINT_ENABLE
extern INT32U
OSTime ;
void mtrace_log_redirect(const char *function, const char *file, int line,

const char *FORMAT, ...)
{

OS_CPU_SR cpu_sr;
//
INT32U tick = ***TimeGet();
//avoid OS_EXIT_CRITICAL in printf

va_list args;


OS_ENTER_CRITICAL();

printf("/n%s (%s,line=%d,tick=%d)/n--" ,function,file,line,OSTime);

va_start (args, FORMAT);

vprintf (FORMAT, args);

va_end (args);

OS_EXIT_CRITICAL();


}
#endif
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐