操作系统内存分配算法与实现

概述

操作系统采用了多种内存分配算法和机制,以管理系统的物理内存资源。这些算法和机制的目标是提供高效的内存分配和回收,以满足不同应用程序和任务的需求。以下是一些常见的 Linux 内存分配算法和机制:

  1. 伙伴系统: 伙伴系统是 Linux内存管理的核心机制之一,用于管理大块物理内存的分配和释放。它将物理内存分割为一系列固定大小的块,然后以 2 的幂次方的大小来组合成伙伴(buddy)块。当分配请求到达时,系统会查找大小最接近请求大小的伙伴块,并将其分割为合适大小的块。这种机制有助于避免内存碎片问题。
  2. SLAB 分配器: SLAB 分配器是一种用于管理小对象分配的内存分配机制。它通过维护三个不同的链表(SLAB、SLOB 和 SLUB),根据对象大小和分配模式来分配和回收内存。SLAB 分配器旨在提高小对象分配的效率,减少内存碎片。
  3. CMA(Contiguous Memory Allocator): CMA 是用于分配连续物理内存块的机制,主要用于需要连续内存的硬件驱动和某些应用场景。CMA 机制允许系统预留一部分连续物理内存,并在需要时进行分配。
  4. Huge Pages: Huge Pages 允许应用程序使用更大的页面(通常为 2MB 或 1GB)来提高性能和内存使用效率。这在大数据处理和内存密集型应用中特别有用。
  5. 内存回收机制: Linux 通过 Page LRU(最近最少使用页面替换算法)和页面交换等机制来进行内存回收。当系统内存不足时,操作系统会尝试通过将不活跃的页面交换到磁盘上来释放内存。
  6. 内存压缩: Linux 也支持内存压缩机制,尝试通过压缩不活跃页面的内容来释放内存。这可以在一些情况下避免频繁的页面交换。
  7. NUMA(Non-Uniform Memory Access)支持: 对于多处理器系统,Linux 提供了 NUMA 支持,以优化内存分配和访问,以减少处理器和内存之间的延迟。

伙伴系统

实现一个完整的伙伴系统内存分配器需要一定的代码量和细致的设计,涉及到内存块的分割、合并、分配和释放等操作。这里提供一个简化的伙伴系统内存分配器的示例,以便您理解其基本原理和部分实现。

#include <stddef.h>

#define MEMORY_POOL_SIZE 1024  // 总内存池大小
#define MIN_BLOCK_SIZE 8       // 最小块大小

typedef struct Block {
    struct Block *next;  // 下一个块
    int size;            // 块的大小
    int free;            // 是否空闲
} Block;

static char memory_pool[MEMORY_POOL_SIZE];  // 内存池
static Block *free_blocks[12];              // 空闲块链表

// 初始化内存分配器
void buddy_init() {
    for (int i = 0; i < 12; ++i) {
        free_blocks[i] = NULL;
    }
    Block *first_block = (Block *)memory_pool;
    first_block->next = NULL;
    first_block->size = MEMORY_POOL_SIZE;
    first_block->free = 1;
    free_blocks[11] = first_block;
}

// 分割块
Block *split_block(Block *block) {
    int new_size = block->size / 2;
    Block *new_block = (Block *)((char *)block + new_size);
    new_block->next = block->next;
    new_block->size = new_size;
    new_block->free = 1;
    block->next = new_block;
    block->size = new_size;
    return new_block;
}

// 合并块
Block *merge_blocks(Block *block) {
    Block *buddy = (Block *)((size_t)block ^ block->size);
    if (buddy->free && buddy->size == block->size) {
        if (buddy < block) {
            block = buddy;
        }
        block->next = buddy->next;
        block->size *= 2;
        merge_blocks(block);
    }
    return block;
}

// 分配内存
void *buddy_alloc(size_t size) {
    if (size <= 0 || size > MEMORY_POOL_SIZE) {
        return NULL;
    }

    int block_size = MIN_BLOCK_SIZE;
    while (block_size < size) {
        block_size *= 2;
    }

    for (int i = block_size / MIN_BLOCK_SIZE - 1; i < 12; ++i) {
        if (free_blocks[i]) {
            Block *block = free_blocks[i];
            free_blocks[i] = block->next;
            block->free = 0;
            while (block->size > block_size) {
                block = split_block(block);
            }
            return (void *)((char *)block + sizeof(Block));
        }
    }
    return NULL;
}

// 释放内存
void buddy_free(void *ptr) {
    if (!ptr) {
        return;
    }
    Block *block = (Block *)((char *)ptr - sizeof(Block));
    block->free = 1;
    merge_blocks(block);
}

int main() {
    buddy_init();

    void *ptr1 = buddy_alloc(32);
    void *ptr2 = buddy_alloc(64);
    void *ptr3 = buddy_alloc(128);

    buddy_free(ptr2);

    return 0;
}

slab内存分配

实现一个完整的 SLAB 分配器需要一定的代码量和细致的设计,涉及到对象的分配、释放、缓存管理等操作。以下是一个简化的 SLAB 分配器的示例,以便您理解其基本原理和部分实现。

#include <stddef.h>
#include <stdlib.h>

#define CACHE_MAX_SIZE 64  // 最大缓存大小

typedef struct Object {
    struct Object *next;
} Object;

typedef struct Cache {
    size_t obj_size;     // 对象大小
    Object *free_list;   // 空闲对象链表
} Cache;

static Cache caches[CACHE_MAX_SIZE];  // 缓存数组

// 初始化缓存
void cache_init() {
    for (size_t i = 0; i < CACHE_MAX_SIZE; ++i) {
        caches[i].obj_size = sizeof(Object) + i;
        caches[i].free_list = NULL;
    }
}

// 从缓存中分配对象
void *cache_alloc(size_t size) {
    if (size <= 0 || size > CACHE_MAX_SIZE) {
        return NULL;
    }
    size_t idx = size - sizeof(Object);
    if (caches[idx].free_list) {
        Object *obj = caches[idx].free_list;
        caches[idx].free_list = obj->next;
        return obj;
    } else {
        return malloc(caches[idx].obj_size);
    }
}

// 释放对象到缓存
void cache_free(void *ptr, size_t size) {
    if (!ptr || size <= 0 || size > CACHE_MAX_SIZE) {
        return;
    }
    size_t idx = size - sizeof(Object);
    Object *obj = (Object *)ptr;
    obj->next = caches[idx].free_list;
    caches[idx].free_list = obj;
}

int main() {
    cache_init();

    void *ptr1 = cache_alloc(16);
    void *ptr2 = cache_alloc(32);

    cache_free(ptr1, 16);
    cache_free(ptr2, 32);

    return 0;
}

CMA内存分配

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>

#define MEMORY_POOL_SIZE 1024  // 总内存池大小

// 定义内存块结构
typedef struct Block {
    struct Block *next;  // 下一个块的指针
    size_t size;         // 块的大小(包括 Block 结构)
    int free;            // 是否空闲
} Block;

static char memory_pool[MEMORY_POOL_SIZE];  // 内存池
static Block *free_block_list = NULL;       // 空闲块链表的头指针

// 初始化 CMA 内存池和空闲块链表
void cma_init() {
    Block *initial_block = (Block *)memory_pool;
    initial_block->next = NULL;
    initial_block->size = MEMORY_POOL_SIZE;
    initial_block->free = 1;
    free_block_list = initial_block;
}

// 从 CMA 内存池中分配连续内存块
void *cma_alloc(size_t size) {
    Block *current_block = free_block_list;  // 从空闲块链表开始遍历
    Block *prev_block = NULL;  // 记录上一个块的指针
    while (current_block) {
        if (current_block->free && current_block->size >= size) {
            if (current_block->size > size) {
                // 如果当前块的大小大于请求的大小,分割块
                Block *new_block = (Block *)((char *)current_block + size);
                new_block->next = current_block->next;
                new_block->size = current_block->size - size;
                new_block->free = 1;
                current_block->next = new_block;
                current_block->size = size;
            }
            current_block->free = 0;  // 标记块为已分配
            return (void *)(current_block + 1);  // 返回实际内存块的指针
        }
        prev_block = current_block;
        current_block = current_block->next;  // 继续遍历下一个块
    }
    return NULL;  // 没有合适大小的块可用
}

// 释放连续内存块到 CMA 内存池
void cma_free(void *ptr) {
    if (!ptr) {
        return;  // 如果指针为空,直接返回
    }
    Block *block = (Block *)((Block *)ptr - 1);  // 获取块的头部指针
    block->free = 1;  // 标记块为空闲

    // 合并相邻的空闲块
    while (block->next && block->next->free) {
        block->size += block->next->size;  // 合并大小
        block->next = block->next->next;    // 移除下一个块
    }
}

int main() {
    cma_init();  // 初始化 CMA

    void *ptr1 = cma_alloc(32);  // 从 CMA 中分配 32 字节大小的连续内存块
    if (ptr1) {
        printf("Allocated memory at address: %p\n", ptr1);
        cma_free(ptr1);  // 释放内存块到 CMA
    } else {
        printf("Failed to allocate memory\n");
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天选码农搬砖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值