📜  二次幂的自由列表分配器|核心记忆分配器(1)

📅  最后修改于: 2023-12-03 15:21:40.420000             🧑  作者: Mango

二次幂的自由列表分配器|核心记忆分配器

简介

在计算机程序中,内存分配是很常见的操作。C/C++等低级语言中更需要程序员手动去管理内存分配。而二次幂的自由列表分配器和核心记忆分配器是两种常见的内存分配器。

二次幂的自由列表分配器是一种内存分配算法,它将请求内存大小按照2的幂等级进行分组,每个等级有自己的空闲链表。当程序需要分配内存时,先通过内存大小找到对应的链表,然后从链表中取出一个空闲块返回给程序。当程序释放内存时,将该内存块插入对应的空闲链表中。

核心记忆分配器是一种能够管理程序运行过程中内存分配的专用分配器。它有两个核心结构,分别是内存池和分配器。内存池是一段预分配的内存区域,分配器则是在内存池中按需分配内存的算法。核心记忆分配器可以提高程序的内存使用效率,减少内存碎片,从而提高程序性能。

二次幂的自由列表分配器
实现原理

二次幂的自由列表分配器将不同大小的内存块按照2的幂等级分组,每个等级对应一个空闲链表。当程序需要内存时,先根据请求的内存大小找到对应的等级,然后从该等级的空闲链表中取出一个内存块,如果链表为空,则向内存池中申请一块足够大的内存,将其拆分成小块并插入到对应的空闲链表中,最后再次从该等级的空闲链表中取出一个内存块并返回给程序。

优缺点

二次幂的自由列表分配器的优点在于:能够有效地减少内存碎片,高效地利用内存,提高程序性能。其缺点是:需要占用更多的内存作为内存池,同时也可能会浪费一些内存。

代码示例
#include <stdlib.h>
#include <stdio.h>

#define BLOCK_SIZE 16    //内存块大小
#define BLOCK_NUM 10     //每个等级空闲链表中的内存块数目
#define LEVEL_NUM 5      //等级数目
#define MEMORY_SIZE 1024 //内存池大小

struct MemoryBlock
{
    struct MemoryBlock* next;
};

struct MemoryLevel
{
    struct MemoryBlock* head;
    unsigned int block_size;
};

void* memory_pool = NULL;
struct MemoryLevel memory_level[LEVEL_NUM];

void MemoryInit()
{
    memory_pool = malloc(MEMORY_SIZE);
    for (int i = 0; i < LEVEL_NUM; i++)
    {
        memory_level[i].head = NULL;
        memory_level[i].block_size = BLOCK_SIZE << i;
        for (int j = 0; j < BLOCK_NUM; j++)
        {
            struct MemoryBlock* new_block = (struct MemoryBlock*)memory_pool + ((1 << i) - 1) * memory_level[i].block_size + j * memory_level[i].block_size;
            new_block->next = memory_level[i].head;
            memory_level[i].head = new_block;
        }
    }
}

void* MemoryAlloc(unsigned int size)
{
    for (int i = 0; i < LEVEL_NUM; i++)
    {
        if (size <= memory_level[i].block_size && memory_level[i].head != NULL)
        {
            void* ret = memory_level[i].head;
            memory_level[i].head = memory_level[i].head->next;
            return ret;
        }
    }
    return NULL;
}

void MemoryFree(void* ptr, unsigned int size)
{
    for (int i = 0; i < LEVEL_NUM; i++)
    {
        if (size == memory_level[i].block_size)
        {
            struct MemoryBlock* block = (struct MemoryBlock*)ptr;
            block->next = memory_level[i].head;
            memory_level[i].head = block;
            break;
        }
    }
}

int main()
{
    MemoryInit();
    void* p1 = MemoryAlloc(3);
    void* p2 = MemoryAlloc(21);
    void* p3 = MemoryAlloc(31);
    MemoryFree(p1, 3);
    MemoryFree(p2, 21);
    MemoryFree(p3, 31);
    return 0;
}
核心记忆分配器
实现原理

核心记忆分配器根据使用频率将内存块分为三个级别:高速内存块、中速内存块和低速内存块。高速内存块是内存使用频率最高的内存块,它们采用的是简单的空闲链表分配方法,以便快速分配和释放内存。中速内存块的内存使用频率较低,采用的是伙伴分配算法,以便维护内存块的连续性。而低速内存块则采用内存页的方式进行管理,在需要时一次性将一整页内存分配出去。

优缺点

核心记忆分配器的优点在于:高效地利用内存,减少内存碎片,并且能够根据内存使用情况和分配策略动态地调整内存池大小。其缺点是:核心记忆分配器比较难以实现,需要程序员具有较高的算法和内存管理知识。

代码示例

由于核心记忆分配器涉及的算法较为复杂,因此在此不提供具体的代码实现。若需要使用核心记忆分配器,建议寻找相关文献或借鉴现有的开源实现。