您的位置:首页 > 其它

lwip—mem_init和mem_malloc详解[转载]

2015-08-21 16:02 323 查看
<pre name="code" class="cpp">#define MEM_ALIGNMENT 4

//对齐方式为4字节对齐

#ifndef LWIP_MEM_ALIGN_SIZE

#define LWIP_MEM_ALIGN_SIZE(size) (((size) + MEM_ALIGNMENT - 1) & ~(MEM_ALIGNMENT-1))

//实现待分配数据空间的内存对齐

#endif

#ifndef LWIP_MEM_ALIGN

//地址对齐,对齐方式也为4字节对齐

#define LWIP_MEM_ALIGN(addr) ((void *)(((mem_ptr_t)(addr) + MEM_ALIGNMENT - 1) & ~(mem_ptr_t)(MEM_ALIGNMENT-1)))

#endif

/* MEM_SIZE: the size of the heap memory. If the application will send

a lot of data that needs to be copied, this should be set high. */

#define MEM_SIZE (8*1024)

//堆的总空间大小,此后在这个基础上划分堆,将在这个空间进行内存分配,内存块结构体和数据都是在这个空间上的

//mem为内存块的结构体,next;,prev都为内存块索引

struct mem {

/** index (-> ram[next]) of the next struct */ //ram为堆的首地址,相当于数组的首地址,索引基地址

mem_size_t next; //next为下一个内存块的索引

/** index (-> ram[next]) of the next struct */

mem_size_t prev; //prev为前一个内存块的索引

/** 1: this area is used; 0: this area is unused */

u8_t used; //标志此内存块已被分配

};

static struct mem *ram_end;

/** All allocated blocks will be MIN_SIZE bytes big, at least!

* MIN_SIZE can be overridden to suit your needs. Smaller values save space,

* larger values could prevent too small blocks to fragment the RAM too much. */

#ifndef MIN_SIZE

#define MIN_SIZE 12

//内存块大小的最小限制,不能小于12

#endif /* MIN_SIZE */

/* some alignment macros: we define them here for better source code layout */

#define MIN_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MIN_SIZE)

//将MIN_SIZE按4字节对齐,即把12按4字节对齐

#define SIZEOF_STRUCT_MEM LWIP_MEM_ALIGN_SIZE(sizeof(struct mem))

//将mem大小按4字节对齐

#define MEM_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEM_SIZE)

//将堆的总空间按4字节对齐,MEM_SIZE在前面,为8*1024

//内存对齐解释看我的博文:/article/1759647.html

/** the heap. we need one struct mem at the end and some room for alignment */

static u8_t ram_heap[MEM_SIZE_ALIGNED + (2*SIZEOF_STRUCT_MEM) + MEM_ALIGNMENT];

//实际开的堆内存空间,MEM_SIZE_ALIGNED为对齐后的数据空间为8192

//堆内存的大小为MEM_SIZE_ALIGNED+(2*SIZEOF_STRUCT_MEM)+MEM_ALIGNMENT=8192+2*MEN结构体的大小+4

void

mem_init(void)

{

struct mem *mem;

//定义一个mem结构体指针变量

LWIP_ASSERT("Sanity check alignment",

(SIZEOF_STRUCT_MEM & (MEM_ALIGNMENT-1)) == 0);

/* align the heap */

ram = LWIP_MEM_ALIGN(ram_heap);

//将堆空间首地址ram_heap按4字节地址对齐

/* initialize the start of the heap */

mem = (struct mem *)ram;

//将堆空间ram 首地址强制转换成mem结构体类型,作为首个内存块,但这个内存块还未使用

mem->next = MEM_SIZE_ALIGNED;

//把首个内存块的next指针指向了堆空间的最后一个地址(MEM_SIZE_ALIGNED为8*1024),后面实际在mem_malloc时会动态调整next索引,

//从而得到实际分配内存空间即为 mem->next减去该内存块mem的地址

//待分配内存块的next索引总是指向堆空间最后,好像也不一定,但是按照思路是这样的。

mem->prev = 0;

//初始化,因为是第一个内存块,所以前一个内存块不存在,故初始化为0

mem->used = 0;

//该内存块没有被分配,待分配状态

/* initialize the end of the heap */

ram_end = (struct mem *)&ram[MEM_SIZE_ALIGNED];

//例化一个堆空间末尾内存块,该内存块指向最后一个地址,标志结尾用的已被分配,不可再分配了

ram_end->used = 1;

//该内存块已被分配

ram_end->next = MEM_SIZE_ALIGNED;

//因为后续再无内存块故,next索引指向最后,即自己

ram_end->prev = MEM_SIZE_ALIGNED;

//这个我也不知道啊

mem_sem = sys_sem_new(1);

/* initialize the lowest-free pointer to the start of the heap */

lfree = (struct mem *)ram;

//初始化空闲对指针,此时首个内存块是空闲的

MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED);

}

void *

mem_malloc(mem_size_t size)

{

mem_size_t ptr, ptr2;

struct mem *mem, *mem2;

#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT

u8_t local_mem_free_count = 0;

#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */

LWIP_MEM_ALLOC_DECL_PROTECT();

if (size == 0) {

return NULL;

}

//size为0的话返回null 分配不成功

/* Expand the size of the allocated memory region so that we can

adjust for alignment. */

size = LWIP_MEM_ALIGN_SIZE(size);

//将待分配数据按4字节进行对齐

if(size < MIN_SIZE_ALIGNED) {

//如果待分配空间小于MIN_SIZE_ALIGNED(12),则返回分配空间也要为12,最小分配空间为12

/* every data block must be at least MIN_SIZE_ALIGNED long */

size = MIN_SIZE_ALIGNED;

}

if (size > MEM_SIZE_ALIGNED) {

//如果待分配空间大于MEM_SIZE_ALIGNED(8*1024),超出堆空间,则返回NULL,无法分配

return NULL;

}

/* protect the heap from concurrent access */

sys_arch_sem_wait(mem_sem, 0);

LWIP_MEM_ALLOC_PROTECT(); //未定义

#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT

/* run as long as a mem_free disturbed mem_malloc */

do {

local_mem_free_count = 0;

#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */

/* Scan through the heap searching for a free block that is big enough,

* beginning with the lowest free block.

*/

//ptr初值=空闲内存块地址与堆内存首地址之差,如果ptr+size小于堆空间总大小8*1024,则可实现相应大小

//的内存块分配,其中ptr实际为已分配了的空间大小,size为待分配的空间大小,两个和一定要小于总空间,才可以实现分配.

//判断完成后,将ptr赋值为该内存块next所指地址

for (ptr = (u8_t *)lfree - ram; ptr < MEM_SIZE_ALIGNED - size;

ptr = ((struct mem *)&ram[ptr])->next) {

//将待分配的这个内存空间初始化为内存块结构体

mem = (struct mem *)&ram[ptr];

#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT //未定义

mem_free_count = 0;

LWIP_MEM_ALLOC_UNPROTECT();

/* allow mem_free to run */

LWIP_MEM_ALLOC_PROTECT();

if (mem_free_count != 0) {

local_mem_free_count = mem_free_count;

}

mem_free_count = 0;

#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */

//ptr为已分配了的内存空间

//后面你会发现,待分配内存块的mem->next始终指向堆空间的最后,即MEM_SIZE_ALIGNED。

//内存块未被使用,此时mem为待分配内存块,故mem->next指向MEM_SIZE_ALIGNED,

//剩余分配空间(MEM_SIZE_ALIGNED-已分配空间-MEM结构体大小)要大于要待分配空间size

if ((!mem->used) &&

(mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) {

/* mem is not used and at least perfect fit is possible:

* mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */

//剩余分配空间(MEM_SIZE_ALIGNED-已分配空间-2*MEM结构体大小-12)

//要大于要待分配空间size,则才可以进行内存分配。

if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) {

/* (in addition to the above, we test if another struct mem (SIZEOF_STRUCT_MEM) containing

* at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem')

* -> split large block, create empty remainder,

* remainder must be large enough to contain MIN_SIZE_ALIGNED data: if

* mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size,

* struct mem would fit in but no data between mem2 and mem2->next

* @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty

* region that couldn't hold data, but when mem->next gets freed,

* the 2 regions would be combined, resulting in more free memory

*/

//ptr2指向新的待分配内存空间

ptr2 = ptr + SIZEOF_STRUCT_MEM + size;

/* create mem2 struct */

//mem2为新的待分配内存块结构体

mem2 = (struct mem *)&ram[ptr2];

//新的内存块mem2未被使用

mem2->used = 0;

//新的待分配的内存块mem2的next索引指向堆空间的最后,即MEM_SIZE_ALIGNED

mem2->next = mem->next;

//而新的内存块的prev索引是我们这次正在分配的模块索引,即ptr

mem2->prev = ptr;

/* and insert it between mem and mem->next */

//把本次分配的mem内存块的next索引重新定位,指向新的待分配的模块的索引,不再指向堆空间最后

mem->next = ptr2;

mem->used = 1;//本内存块被使用

//我之前分析的都是新的待分配内存块next索引应该始终指向堆空间最后的,这里竟然判断了,可能存在不指向最后的情况

//具体原因还没分析。如果新的待分配内存块mem2的next索引未指向最后,则需要将它所指向的索引内存块的prev索引指向

//他自己ptr2。

if (mem2->next != MEM_SIZE_ALIGNED) {

((struct mem *)&ram[mem2->next])->prev = ptr2;

}

MEM_STATS_INC_USED(used, (size + SIZEOF_STRUCT_MEM));

} else {//如果没有满足对应if条件,则直接分配完改内存块即可,也不用指向下一个待分配的内存块,因为没有空间可以再分配了

/* (a mem2 struct does no fit into the user data space of mem and mem->next will always

* be used at this point: if not we have 2 unused structs in a row, plug_holes should have

* take care of this).

* -> near fit or excact fit: do not split, no mem2 creation

* also can't move mem->next directly behind mem, since mem->next

* will always be used at this point!

*/

mem->used = 1;

MEM_STATS_INC_USED(used, mem->next - ((u8_t *)mem - ram));

}

if (mem == lfree) {//将空闲指针索引指向新的待分配内存块索引ram[lfree->next],即ptr2

/* Find next free block after mem and update lowest free pointer */

while (lfree->used && lfree != ram_end) {

LWIP_MEM_ALLOC_UNPROTECT();

/* prevent high interrupt latency... */

LWIP_MEM_ALLOC_PROTECT();

lfree = (struct mem *)&ram[lfree->next];

}

LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used)));

}

LWIP_MEM_ALLOC_UNPROTECT();

sys_sem_signal(mem_sem);

LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.",

(mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end);

LWIP_ASSERT("mem_malloc: allocated memory properly aligned.",

((mem_ptr_t)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0);

LWIP_ASSERT("mem_malloc: sanity check alignment",

(((mem_ptr_t)mem) & (MEM_ALIGNMENT-1)) == 0);

return (u8_t *)mem + SIZEOF_STRUCT_MEM;//返回分配结果,即已分配内存块数据空间的首地址。

}

}

#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT

/* if we got interrupted by a mem_free, try again */

} while(local_mem_free_count != 0);

#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */

LWIP_DEBUGF(MEM_DEBUG | 2, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size));

MEM_STATS_INC(err);

LWIP_MEM_ALLOC_UNPROTECT();

sys_sem_signal(mem_sem);

return NULL;

}

文章转自:http://blog.csdn.net/lg2lh
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: