基本数据结构
1:memtype
//基础数据结构最后都会被封装成这个结构
struct memtype {
struct memtype *next, **ref;
const char *name; //结构描述名
atomic_size_t n_alloc; //申请内存的长度
atomic_size_t n_max;
atomic_size_t size; //已用长度
#ifdef HAVE_MALLOC_USABLE_SIZE
atomic_size_t total;
atomic_size_t max_size;
#endif
};
//其中atomic_size_t 即 volatile size_t
typedef _Atomic size_t atomic_size_t;
#define _Atomic volatile
2:memgroup
struct memgroup {
struct memgroup *next, **ref;
struct memtype *types, **insert;
const char *name; //组名
/* ignore group on dumping memleaks at exit */
bool active_at_exit;
};
方法
1:结构体声明初始化
//结构extern申明
#define DECLARE_MTYPE(name) \
extern struct memtype MTYPE_##name[1]; \
/* end */
#define DEFINE_MTYPE_ATTR(group, mname, attr, desc) \
//结构声明,并初始化在.data.mtypes数据段中
attr struct memtype MTYPE_##mname[1] \
__attribute__((section(".data.mtypes"))) = { { \
.name = desc, \
.next = NULL, \
.n_alloc = 0, \
.size = 0, \
.ref = NULL, \
} }; \
//在main前指定优先级1001执行该函数
static void _mtinit_##mname(void) __attribute__((_CONSTRUCTOR(1001))); \
static void _mtinit_##mname(void) \
{ \
if (_mg_##group.insert == NULL) \
_mg_##group.insert = &_mg_##group.types; \
MTYPE_##mname->ref = _mg_##group.insert; \
*_mg_##group.insert = MTYPE_##mname; \
_mg_##group.insert = &MTYPE_##mname->next; \
} \
static void _mtfini_##mname(void) __attribute__((_DESTRUCTOR(1001))); \
static void _mtfini_##mname(void) \
{ \
if (MTYPE_##mname->next) \
MTYPE_##mname->next->ref = MTYPE_##mname->ref; \
*MTYPE_##mname->ref = MTYPE_##mname->next; \
} \
/* end */
#define DEFINE_MTYPE(group, name, desc) \
DEFINE_MTYPE_ATTR(group, name, , desc) \
/* end */
#define DEFINE_MTYPE_STATIC(group, name, desc) \
DEFINE_MTYPE_ATTR(group, name, static, desc) \
/* end */
其中:
1:使用__attribute__((section()))构建初始化函数表,由模块告知main:“我要初始化“,添加新模块再也不需要在main代码中显式调用模块初始化接口。以此实现main与模块之间的隔离,main不再关心有什么模块,模块的删减也不需要修改main。
模块通过__attribute__((section("name")))的实现,在编译时把初始化的接口放到name数据段中。main在执行初始化时并不需要知道有什么模块需要初始化,只需要把name数据段中的所有初始化接口执行一遍即可
__attribute__((section(”name“)))是gcc编译器支持的一个编译特性(arm编译器也支持此特性),实现在编译时把某个函数/数据放到name的数据段中。
2:__attribute__((constructor(preference))) 先于main()函数调用
具体可参考__attribute__((constructor))和__attribute__((destructor)) 。
2:内存分配
//用calloc分配size大小内存块
#define XCALLOC(mtype, size) qcalloc(mtype, size)
void *qcalloc(struct memtype *mt, size_t size)
{
//用calloc分配size个长度为1字节的内存,赋给函数mt_checkalloc的ptr
return mt_checkalloc(mt, calloc(size, 1), size);
}
static inline void *mt_checkalloc(struct memtype *mt, void *ptr, size_t size)
{
//(ptr == NULL) == 0的概率很大,即calloc一般不会分配失败
if (__builtin_expect(ptr == NULL, 0)) {
if (size) {
/* malloc(0) is allowed to return NULL */
memory_oom(size, mt->name);
}
return NULL;
}
//内存分配成功,对mt内数据结构的数值进行原子跟新
mt_count_alloc(mt, size, ptr);
return ptr;
}