uip协议栈分析(2)

uip的内存管理方法:

    内存管理的实现在memb.c/memb.h里。

    这两个文件负责uip的内存块的管理,内存块是由MEMB()宏声明。内存从声明的内存块里用memb_alloc()分配,用memb_free()释放。因为命名空间的冲突,每个C模块只能有一个MEMB()宏声明。

先看memb.h文件:

#define MEMB_CONCAT2(s1, s2) s1##s2

#define MEMB_CONCAT(s1, s2)  MEMB_CONCAT2(s1, s2)

这两个宏很容易看出来是连接两个字符串的。

       #define MEMB(name, structure, num) /

        static char MEMB_CONCAT(name,_memb_count)[num]; /

        static structure MEMB_CONCAT(name,_memb_mem)[num]; /

        static struct memb_blocks name = {sizeof(structure), num, /

                                          MEMB_CONCAT(name,_memb_count), /

                                    (void*)MEMB_CONCAT(name,_memb_mem)}

这个宏用来声明一个数组,这个数组是由多个特定大小的内存块组成。第一个参数用来作为内存块的名字标示,第二个参数是内存块中的子块的数据结构,第三个参数是内存块中子块的数目。

static char MEMB_CONCAT(name,_memb_count)[num];这句明显可以看出来是声明一个数组,表示子块的引用计数,展开后就是static char name_memb_count[num]。

static structure MEMB_CONCAT(name,_memb_mem)[num];这句就是静态数组用来分配实际内存的,展开后就是static structure name_memb_mem[num]。包含num个子块的内存,内存的数据类型是structure。

       static struct memb_blocks name = {sizeof(structure), num, /

                              MEMB_CONCAT(name,_memb_count), /

                              (void *)MEMB_CONCAT(name,_memb_mem)}

这句声明一个指定名字的内存块,并为内存块结构体赋值,内存块结构体memb_blocks:

struct memb_blocks {

  unsigned short size;  //子块的大小

  unsigned short num;  //子块的数目

  char *count;  //每个子块引用计数,表示正在使用还是未被使用

  void *mem;  //内存块首地址

};

 

再看memb.c:

void  memb_init(struct memb_blocks *m)

{

  memset(m->count, 0, m->num);

  memset(m->mem, 0, m->size * m->num);

}

这个函数把前面用MEMB宏声明的内存块初始化,即把memb_blocks结构体里的count和mem项清零。参数m就是用MEMB声明的name。

       void *  memb_alloc(struct memb_blocks *m)

{

int i;

             

for(i = 0; i < m->num; ++i) {

if(m->count[i] == 0) {

/* 如果子块未被使用, 增加应用计数表示现在被使用,并且返回指向这个内存块的指针*/

++(m->count[i]);

return (void *)((char *)m->mem + (i * m->size));

}

}

 

/* 未发现空闲块, 返回NULL表示分配内存失败*/

return NULL;

}

 

       char memb_free(struct memb_blocks *m, void *ptr)

{

int i;

char *ptr2;

             

/* 遍历内存块列表试图找到ptr指针指向的内存子块*/

ptr2 = (char *)m->mem;

for(i = 0; i < m->num; ++i) {

                  if(ptr2 == (char *)ptr) {

/* 找到ptr指向的内存子块,减少引用计数并返回新的计数值 */

if(m->count[i] > 0) {

/*确保没有减少未使用的内存子块引用计数 */

--(m->count[i]);

}

return m->count[i];

}

ptr2 += m->size;

}

return -1;

}

 

     App目录下的telnetd.c正好用到了memb.c里的函数:

struct telnetd_line {

  char line[TELNETD_CONF_LINELEN];

};

MEMB(linemem, struct telnetd_line, TELNETD_CONF_NUMLINES);

 

memb_init(&linemem);   memb_alloc(&linemem);    memb_free(&linemem, line);

    使用起来非常方便容易,缺点是只能分配固定大小的子块。但至少不会产生内存碎片了,而且由于是静态声明的,会自动进行对齐。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值