用户定义的内存管理
malloc()
经常调用底层操作系统函数来获取内存页面。但是这个函数并没有什么特别的,它可以通过声明一个大的静态数组并从中分配来直接实现(确保正确对齐有一点点困难,实际上对齐到 8 个字节几乎总是足够的)。
为了实现简单的方案,控制块存储在紧接在从调用返回的指针之前的存储器区域中。这意味着可以通过从返回的指针中减去并读取控制信息来实现 free()
,控制信息通常是块大小加上允许将其放回空闲列表中的一些信息 - 未分配块的链接列表。
当用户请求分配时,搜索空闲列表,直到找到与所请求的数量相同或更大的块,然后在必要时将其拆分。如果用户不断地进行许多分配并且不可预测的大小并且以不可预测的间隔(并非所有真实程序都像这样,简单的方案通常适用于小程序),这可能导致内存碎片。
/* typical control block */
struct block
{
size_t size; /* size of block */
struct block *next; /* next block in free list */
struct block *prev; /* back pointer to previous block in memory */
void *padding; /* need 16 bytes to make multiple of 8 */
}
static struct block arena[10000]; /* allocate from here */
static struct block *firstfree;
许多程序需要大量分配相同大小的小对象。这很容易实现。只需使用带有下一个指针的块。因此,如果需要 32 字节的块:
union block
{
union block * next;
unsigned char payload[32];
}
static union block arena[100];
static union block * head;
void init(void)
{
int i;
for (i = 0; i < 100 - 1; i++)
arena[i].next = &arena[i + 1];
arena[i].next = 0; /* last one, null */
head = &block[0];
}
void *block_alloc()
{
void *answer = head;
if (answer)
head = head->next;
return answer;
}
void block_free(void *ptr)
{
union block *block = ptr;
block->next = head;
head - block;
}
该方案非常快速和有效,并且可以在一定的清晰度下变得通用。