我正在尝试为练习创建自己的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岁那样解释,我很难理解这个概念。
答案 0 :(得分:5)
扩展流程数据段不会影响其他流程。在大多数(最近的)架构上,进程内存模型是平坦的,即每个进程都有virtual
地址空间(2^32
或2^64
字节)。当进程请求额外的内存(页面)时,会添加virtual
内存进行处理。实际上,这并不意味着发生任何物理内存分配,因为virtual
内存可以映射到交换文件,或者在使用之前完全取消映射(地址被赋予进程,但没有分配给它的实际资源)。内核负责根据需要/每个资源的可用性将物理地址映射到virtual
。
算法的作用是什么?
当用户调用malloc
时,算法会尝试查找可用的空块。在开始时,没有,所以算法尝试扩展过程数据段。
但是,您可以看到free
不释放虚拟内存(因为它不像分配虚拟内存那样简单),而是将此released
块添加到未使用的块列表中。
因此,当有预先发布的块时,malloc
会尝试重用它们而不是extendind数据段。
标准malloc
的工作原理如上:不。您提供的示例很简单,但效率却很低。有许多不同的算法可用于内存管理:小块堆(当分配数据达到一定数量时具有O(1)
性能),特定于线程的分配器(减少从多个线程访问堆的拥塞),分配器, - 分配大块然后使用它们(类似于上面,但更有效)和其他。
您可以尝试使用“内存堆实现”获取更多信息