【发布时间】:2016-04-14 19:58:25
【问题描述】:
我已经用 C 语言构建了一个简单的内存池,并且我还实现了在这个池中实现内存块的能力。
内存块本身非常简单,只是一个带有空闲标志和大小属性的双向链表。
我现在要做的是创建一个函数,该函数接受指向我的内存池的指针并对内部的内存块进行碎片整理,以便分配的(空闲 == 0)块朝向池的开头,而解除分配的块是靠近游泳池的尽头。
例如,如果我在调用碎片整理函数之前有这样的内存块结构:
Block Size: 25 (41 w/ header), Free: 1
Block Size: 100 (116 w/ header), Free: 0
Block Size: 25 (41 w/ header), Free: 1
Block Size: 100 (116 w/ header), Free: 0
Block Size: 100 (116 w/ header), Free: 0
Block Size: 54 (70 w/ header), Free: 1
然后在调用我的函数后,块将被安排如下:
Block Size: 100 (116 w/ header), Free: 0
Block Size: 100 (116 w/ header), Free: 0
Block Size: 100 (116 w/ header), Free: 0
Block Size: 25 (41 w/ header), Free: 1
Block Size: 25 (41 w/ header), Free: 1
Block Size: 54 (70 w/ header), Free: 1
我已经尝试构建该函数,但是在移动正确的块时遇到了问题,因为这是调用该函数后的输出:
Block Size: 100 (116 w/ header), Free: 0
Block Size: 25 (41 w/ header), Free: 1
Block Size: 100 (116 w/ header), Free: 0
Block Size: 1744830464 (1744830480 w/ header), Free: 21
我完全不确定该函数在哪里执行了不正确的操作,因此希望有人可以为我阐明这一点。
我的碎片整理功能:
void defragment(Pool* pool)
{
if(pool && pool->root)
{
Block* current = pool->root;
while(current)
{
if(!current->free)
{
Block* current_prev = current->prev;
if(current_prev && current_prev->free)
{
Block* prev_prev = current_prev->prev;
int new_block_size = current_prev->size;
Block* moved_current = memmove(current_prev, current, sizeof(Block) + current->size);
if(!moved_current)
{
printf("couldn't move memory\n");
}
else
{
Block* new_block = initBlock((((char*)moved_current) + sizeof(Block) + moved_current->size), new_block_size);
new_block->prev = moved_current;
new_block->next = moved_current->next;
moved_current->prev = prev_prev;
moved_current->next = new_block;
if(prev_prev)
{
prev_prev->next = moved_current;
}
current = moved_current;
continue;
}
}
}
current = current->next;
}
//Join Contiguous Blocks
}
}
对 initBlock 函数的调用只需要一个内存地址,将其视为一个 Block 结构,然后将 free 属性设置为 true 并将 size 属性设置为给定的大小。
我正在使用带有 -std=C99 标志的 GCC 编译器。
【问题讨论】:
-
已分配块的所有者在重新定位后会做什么?
-
@WeatherVane 目前,我不需要拥有所有者的指针,因为这是为 uni 分配的。虽然有一个分配的中间目录并让指针保持不变会给我带来更高的分数,但这不是低分数的要求。
-
碎片整理程序不知道用户将内存指针放在哪里,因此您无法更新它们。当然,您只能对未使用的区域进行碎片整理。就像对硬盘进行碎片整理时一样,打开的文件无法移动。
-
对不起,那太荒谬了 (@Liam)。内存池中没有任何意义,它的内存可能会从您的下方移出。
标签: c memory memory-management heap-memory defragmentation