Malloc实现 - 困惑

时间:2013-04-13 20:10:34

标签: c

我正在尝试为练习创建自己的malloc()。我从这个thread.

获得了以下代码
typedef struct free_block {
    size_t size;
    struct free_block* next;
} free_block;

static free_block free_block_list_head = { 0, 0 };

// static const size_t overhead = sizeof(size_t);

static const size_t align_to = 16;

void* malloc(size_t size) {
    size = (size + sizeof(free_block) + (align_to - 1)) & ~ (align_to - 1);
    free_block* block = free_block_list_head.next;
    free_block** head = &(free_block_list_head.next);
    while (block != 0) {
        if (block->size >= size) {
            *head = block->next;
            return ((char*)block) + sizeof(free_block);
        }
        head = &(block->next);
        block = block->next;
    }

    block = (free_block*)sbrk(size);
    block->size = size;

    return ((char*)block) + sizeof(free_block);
}

void free(void* ptr) {
    free_block* block = (free_block*)(((char*)ptr) - sizeof(free_block ));
    block->next = free_block_list_head.next;
    free_block_list_head.next = block;
}

我对将内存块视为链表感到困惑。在我看来,每当我们需要内存时,我们就会基本上调用sbrk(),并检查我们之前请求的一些内存是否在此期间没有被释放。

但我们无法检查属于其他进程的其他内存块,我们只检查之前请求的内存并添加到链接列表中。

如果是这种情况,这是最佳的吗?这是标准malloc()的工作原理吗? 我们有办法处理堆上的所有内存吗?

请像我5岁那样解释,我很难理解这个概念。

1 个答案:

答案 0 :(得分:5)

扩展流程数据段不会影响其他流程。在大多数(最近的)架构上,进程内存模型是平坦的,即每个进程都有virtual地址空间(2^322^64字节)。当进程请求额外的内存(页面)时,会添加virtual内存进行处理。实际上,这并不意味着发生任何物理内存分配,因为virtual内存可以映射到交换文件,或者在使用之前完全取消映射(地址被赋予进程,但没有分配给它的实际资源)。内核负责根据需要/每个资源的可用性将物理地址映射到virtual

算法的作用是什么?

当用户调用malloc时,算法会尝试查找可用的空块。在开始时,没有,所以算法尝试扩展过程数据段。

但是,您可以看到free不释放虚拟内存(因为它不像分配虚拟内存那样简单),而是将此released块添加到未使用的块列表中。

因此,当有预先发布的块时,malloc会尝试重用它们而不是extendind数据段。

标准malloc的工作原理如上:不。您提供的示例很简单,但效率却很低。有许多不同的算法可用于内存管理:小块堆(当分配数据达到一定数量时具有O(1)性能),特定于线程的分配器(减少从多个线程访问堆的拥塞),分配器, - 分配大块然后使用它们(类似于上面,但更有效)和其他。

您可以尝试使用“内存堆实现”获取更多信息