contiki系统分析四:内存分配
Posted 王玉成的博客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了contiki系统分析四:内存分配相关的知识,希望对你有一定的参考价值。
contiki有三种分配内存的方式。
memb 内存块分配器,在contiki中使用最频繁
mmem 管理内存分配器,很少去使用
标准C库的malloc的栈内存分配器,在contiki这种受限系统中使有最危险。
memb的内存分配器
有下列的API:
MEMB(name, structure, num) : 定义memory block.
void memb_init(struct memb *m) : 初始化memory block.
void *memb_alloc(struct memb *m) : 分配memory block.
int memb_free(struct memb *m, void *ptr) : 释放memory block.
int memb_inmemb(struct memb *m, void *ptr) : 判断ptr传入的地址是否是memory block.
MEMB做了哪些事情
#define MEMB(name, structure, num) \\
static char CC_CONCAT(name,_memb_count)[num]; \\
static structure CC_CONCAT(name,_memb_mem)[num]; \\
static struct memb name = sizeof(structure), num, \\
CC_CONCAT(name,_memb_count), \\
(void *)CC_CONCAT(name,_memb_mem)
struct memb
unsigned short size;
unsigned short num;
char *count;
void *mem;
;
主要是定义了mem block.
其中CC_CONCAT这个宏把两个参数连接成为一个字符串.
name表示要定义的这个memblock的名称.
num表示memblock的数量,但是在struct memb中把num存储的大小定义为unsigned short型,也就是说,最多存隼128个memblock的对象
strructure参数表示需要扩展内存的结构体.
先定义出记录mem block对象的指针,和内容.然后再把信息记录在memb的结构体中.记录内存的状态跟分配内存是在同一时间完成的.
其中定义了两个数组
count:表示这段内存空间有没有被使用(0表示没使用,1表示已经使用),首地址memb->count
mem:实际的结构体指针存放的数组,首地址memb->mem,其它元素访问memb->mem+i*memb->size
memb->size是存放的sizeof(structure)的值.
num就表示分配数量,实际上mem的总大小为memb->size * memb->num
另外要注意的是,MEMB开辟的内存空间都是用static定义的,count和mem这两个数组由于没赋初值,放在.bss段里,但是memb name赋了初值,放在.data段里.众所周知,传统的C库中的malloc一系列的函数,是在heap中存放开辟的空间的.
由于内存受限系统不能去开辟一段自由使用的空间,而且contiki中的轻量级线程也没有自己的堆和栈.所以放在data或bss段中是比较好的办法.
memb_init
把已经开辟的空间里的所有值都设为0.用memset实现.
memb_alloc
从memb->count[0]开始往后找大小为mem->size的内存块,
如果memb->count[i]标记为1,则这个区块已经使用,继续向后找.
如果标记为0,则把区块分配出去.返回memb->mem +i*memb->size
如果返回NULL,则标记为0.
memb_free
有两个参数,一个是memb结构体的参数,另一个是要free掉的指针.
函数的实现流程是,在memb->mem数组中去掉传入的指针.如果找到.则把memb->count[i]标记为0.然后返回0
没找到这个指针,则返回为-1.
memb_inmemb
去查找传入参数是否是memb分配的地址.也就是看传入参数是否落在memb->mem的区间中.若是返回1,不是返回0.
下面是一个调用API的示例
struct connection
int socket;
;
MEMB(connections, struct connection, 16);
struct connection *
open_connection(int socket)
struct connection *conn;
conn = memb_alloc(&connections);
if(conn == NULL)
return NULL;
conn->socket = socket;
return conn;
void
close_connection(struct connection *conn)
memb_free(&connections, conn);
mmem管理内存分配器
模型:
mmem(managed memory allocator)
实现的文件是core/lib/mmem.c及对应的头文件.
中间涉及一个结构体:
struct mmem
struct mmem *next;
unsigned int size;
void *ptr;
;
大体的思路,还是用static类型的全局变量.是字符型的数组.数组大小默认4096,也就是4096字节.这个参数可用MMEM_CONF_SIZE进行配置.
然后mmem_init()初始化上图所示的链表.
mmem_alloc()则是分配一段连续的内存.然后在链表中记录下来.
其中用了一个技巧.
/* Check if we have enough memory left for this allocation. */
if(avail_memory < size)
return 0;
/* We had enough memory so we add this memory block to the end of
the list of allocated memory blocks. */
list_add(mmemlist, m);
/* Set up the pointer so that it points to the first available byte
in the memory block. */
m->ptr = &memory[MMEM_SIZE - avail_memory];
/* Remember the size of this memory block. */
m->size = size;
/* Decrease the amount of available memory. */
avail_memory -= size;
avail_memory是一个全局变量.MMEM_SIZE是分配的内存空间的总大小.则MMEM_SIZE-avail_memory就是还没有分配的内存的起始的数组索引.
这也意味着,在这段内存空间里,已分配的内存始终在前面,未分配的内存始终在后面.这样做的话,也有合理性.在内存分配时,不存在内存碎片.
mmem->size是当前分配内存的大小. mmem->ptr是当前分配内存的起始地址.
mmem_free(),有一个参数,即当前分配内存的mmem结构体.实现是,利用memmove,把后面已分配内存的空间的数据覆盖掉刚才要free掉的内存.然后再从链表中删除要free的mmem的记录.
static struct mmem mmem;
static void
test_mmem(void)
struct my_struct
int a;
my_data, *my_data_ptr;
if(mmem_alloc(&mmem, sizeof(my_data)) == 0)
printf("memory allocation failed\\n");
else
printf("memory allocation succeeded\\n");
my_data.a = 0xaa;
memcpy(MMEM_PTR(&mmem), &my_data, sizeof(my_data));
printf("Value a equals 0x%x\\n",
((struct my_struct *)MMEM_PTR(&mmem))->a);
mmem_free(&mmem);
示例代码,没有分析的必要了.
这种操作在中断,多线程及抢占式的代码存在的情况下,极不安全.所以一般只是在contiki的进程中使用.如果获取分配的内存地址,只能用MMEM_PTR()这个宏.
在contiki系统中,可以在platform下面的初始化代码时提供mmem_init.
platform/iris/contiki-iris-main.c有对应的例子.可以看一下.
总结
第三种分配内存的方法即C库里的malloc, calloc等函数.但是在contiki内存受限.不会分配到连续的内存,而且也要开足heap区间.对contiki来说,不是一个好的选择.
memb的话,属于静态的分配内存.mmem属于动态分配内存.
但是现在的contiki系统中通用的做法是静态分配内存.好的方法应该是动态去分配.
以上是关于contiki系统分析四:内存分配的主要内容,如果未能解决你的问题,请参考以下文章