一个简单的可移植 模块/系统动态内存 跟踪方法
2010-08-09 15:25
495 查看
一个简单的可移植
模块/系统动态内存
跟踪方法
在嵌入式系统或一些内存申请,释放频繁的场合,很难统计当前使用的动态内存,和整个软件模块运行过程中的内存使用的峰值;或者模块卸载时内存有无完全释放,还有就是动态内存的踩踏检查。针对这种需求,本文给出一种
简单的解决办法,并用 c code
描述出来。
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
模块/系统动态内存
跟踪方法
在嵌入式系统或一些内存申请,释放频繁的场合,很难统计当前使用的动态内存,和整个软件模块运行过程中的内存使用的峰值;或者模块卸载时内存有无完全释放,还有就是动态内存的踩踏检查。针对这种需求,本文给出一种
简单的解决办法,并用 c code
描述出来。
感性认识
本文命名所建立的跟踪模块为mtracemtrace可以用来
跟踪当前
系统/模块的内存
使用情况
,以及估算系统/模块的占用内存的极值
,
系统/模块
卸载时的
内存
泄露情况。
模块内存跟踪只在
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
相关文章推荐
- 使用.NET REACTOR使用方法,制作软件许可证,做一个简单的许可证系统步骤
- 快讯:黑客找到一个破解虹膜生物安全系统的简单方法
- 简单的proc动态文件系统模块
- 一个简单的动态页面转静页面的方法
- 一个简单的内存同步到数据库的方法
- 一个简单的内存检查系统
- 做的一个培训机构用跟踪生源的简单系统(VS2008+Sql-server express 2005)
- 关于二维数组的动态内存分配的一个比较好的方法
- C# 判断32位还是64位系统的一个简单方法(当然目标平台不能是x86)
- 一个简单的 动态页面 生成 静页面的方法
- 从webconfig中动态调用web服务,找到的一个简单方法!!!!
- 一个简单的模板系统的实现(动态载入DLL)
- 使用Java编写一个简单的Web的监控系统cpu利用率,cpu温度,总内存大小
- 一个简单的动态页面转静页面的方法
- 一个简单的跟踪用户访问路径的方法
- 利用运行时,给UIImageView写一个分类,交换里面的setImage的方法,可以重绘图片,提高内存的利用率(要是没有重绘图片,直接使用系统提供的setImag就会造成占用大量的内存问题)
- 一个很好的内存泄露跟踪的方法
- 给自己做的项目添加开机动画,只是一个简单的添加方法,如果系统的方法太麻烦的画,就试试我这个吧,但是如果是想专业一些的话,还是学习系统的吧!!!
- 一个简单的动态页面转静页面的方法
- 一个动态内存管理模块的实现