编辑
2025-03-19
linux开发
0
请注意,本文编写于 297 天前,最后修改于 297 天前,其中某些信息可能已经过时。

目录

用户层内存池
内存池结构体
初始化内存池
从内存池中分配内存
释放内存到内存池
销毁内存池
示例使用
解释
多线程安全
注意事项
补充
代码分析
举例说明
第一次循环(i = 0):
第二次循环(i = 1):
第三次循环(i = 2):
最终结果
为什么用链表?

用户层内存池

先阅读以下代码

c
#include <stdio.h> #include <stdlib.h> #include <pthread.h> #define POOL_SIZE 1024 // 内存池大小 #define BLOCK_SIZE 1024 // 每个内存块的大小 typedef struct MemoryBlock { struct MemoryBlock* next; } MemoryBlock; typedef struct MemoryPool { MemoryBlock* freeList; // 空闲内存块链表 char* memory; // 内存池的实际内存 pthread_mutex_t lock; // 互斥锁,用于线程安全 } MemoryPool; MemoryPool* createMemoryPool() { MemoryPool* pool = (MemoryPool*)malloc(sizeof(MemoryPool)); if (!pool) return NULL; pool->memory = (char*)malloc(POOL_SIZE * BLOCK_SIZE); if (!pool->memory) { free(pool); return NULL; } pool->freeList = NULL; for (int i = 0; i < POOL_SIZE; i++) { MemoryBlock* block = (MemoryBlock*)(pool->memory + i * BLOCK_SIZE); block->next = pool->freeList; pool->freeList = block; } pthread_mutex_init(&pool->lock, NULL); return pool; } void* allocateFromPool(MemoryPool* pool) { pthread_mutex_lock(&pool->lock); if (!pool->freeList) { pthread_mutex_unlock(&pool->lock); return NULL; // 内存池已满 } MemoryBlock* block = pool->freeList; pool->freeList = block->next; pthread_mutex_unlock(&pool->lock); return (void*)block; } void freeToPool(MemoryPool* pool, void* ptr) { if (!ptr) return; pthread_mutex_lock(&pool->lock); MemoryBlock* block = (MemoryBlock*)ptr; block->next = pool->freeList; pool->freeList = block; pthread_mutex_unlock(&pool->lock); } void destroyMemoryPool(MemoryPool* pool) { if (!pool) return; pthread_mutex_destroy(&pool->lock); free(pool->memory); free(pool); } int main() { MemoryPool* pool = createMemoryPool(); if (!pool) { printf("Failed to create memory pool\n"); return 1; } void* ptr1 = allocateFromPool(pool); void* ptr2 = allocateFromPool(pool); if (ptr1 && ptr2) { printf("Allocated memory blocks: %p, %p\n", ptr1, ptr2); } freeToPool(pool, ptr1); freeToPool(pool, ptr2); destroyMemoryPool(pool); return 0; }

以下为解析
这个内存池使用了互斥锁来确保线程安全。

内存池结构体

c
#include <stdio.h> #include <stdlib.h> #include <pthread.h> #define POOL_SIZE 1024 // 内存池大小 #define BLOCK_SIZE 64 // 每个内存块的大小 typedef struct MemoryBlock { struct MemoryBlock* next; } MemoryBlock; typedef struct MemoryPool { MemoryBlock* freeList; // 空闲内存块链表 char* memory; // 内存池的实际内存 pthread_mutex_t lock; // 互斥锁,用于线程安全 } MemoryPool;

初始化内存池

c
MemoryPool* createMemoryPool() { MemoryPool* pool = (MemoryPool*)malloc(sizeof(MemoryPool)); if (!pool) return NULL; pool->memory = (char*)malloc(POOL_SIZE * BLOCK_SIZE); if (!pool->memory) { free(pool); return NULL; } pool->freeList = NULL; for (int i = 0; i < POOL_SIZE; i++) { MemoryBlock* block = (MemoryBlock*)(pool->memory + i * BLOCK_SIZE); block->next = pool->freeList; pool->freeList = block; } pthread_mutex_init(&pool->lock, NULL); return pool; }

从内存池中分配内存

c
void* allocateFromPool(MemoryPool* pool) { pthread_mutex_lock(&pool->lock); if (!pool->freeList) { pthread_mutex_unlock(&pool->lock); return NULL; // 内存池已满 } MemoryBlock* block = pool->freeList; pool->freeList = block->next; pthread_mutex_unlock(&pool->lock); return (void*)block; }

释放内存到内存池

c
void freeToPool(MemoryPool* pool, void* ptr) { if (!ptr) return; pthread_mutex_lock(&pool->lock); MemoryBlock* block = (MemoryBlock*)ptr; block->next = pool->freeList; pool->freeList = block; pthread_mutex_unlock(&pool->lock); }

销毁内存池

c
void destroyMemoryPool(MemoryPool* pool) { if (!pool) return; pthread_mutex_destroy(&pool->lock); free(pool->memory); free(pool); }

示例使用

c
int main() { MemoryPool* pool = createMemoryPool(); if (!pool) { printf("Failed to create memory pool\n"); return 1; } void* ptr1 = allocateFromPool(pool); void* ptr2 = allocateFromPool(pool); if (ptr1 && ptr2) { printf("Allocated memory blocks: %p, %p\n", ptr1, ptr2); } freeToPool(pool, ptr1); freeToPool(pool, ptr2); destroyMemoryPool(pool); return 0; }

解释

  1. MemoryPool 结构体:包含一个空闲内存块链表 freeList,实际内存 memory,以及一个互斥锁 lock
  2. createMemoryPool:初始化内存池,分配内存并将所有内存块链接到空闲链表中。
  3. allocateFromPool:从空闲链表中分配一个内存块,如果链表为空则返回 NULL
  4. freeToPool:将内存块释放回空闲链表。
  5. destroyMemoryPool:销毁内存池,释放所有内存。

多线程安全

通过使用 pthread_mutex_lockpthread_mutex_unlock,确保了在多线程环境下对内存池的操作是线程安全的。

注意事项

  • 这个实现是一个简单的内存池,适用于小块内存的频繁分配和释放。
  • 如果内存池的大小和块大小不合适,可能会导致内存浪费或频繁的内存分配失败。
  • 实际应用中,可能需要更复杂的内存管理策略,例如动态扩展内存池、支持不同大小的内存块等。

补充

这段代码的作用是将内存池中的内存块初始化为一个空闲链表。让我们逐步分析这段代码,帮助你更好地理解。


代码分析

c
for (int i = 0; i < POOL_SIZE; i++) { MemoryBlock* block = (MemoryBlock*)(pool->memory + i * BLOCK_SIZE); block->next = pool->freeList; pool->freeList = block; }
  1. pool->memory

    • pool->memory 是内存池的实际内存区域,它是一个连续的内存块,大小为 POOL_SIZE * BLOCK_SIZE
    • 这段内存被划分为 POOL_SIZE 个小的内存块,每个内存块的大小为 BLOCK_SIZE
  2. MemoryBlock* block = (MemoryBlock*)(pool->memory + i * BLOCK_SIZE)

    • 通过 pool->memory + i * BLOCK_SIZE,我们计算第 i 个内存块的起始地址。
    • 将这个地址强制转换为 MemoryBlock* 类型,表示一个内存块。
  3. block->next = pool->freeList

    • block->next 是当前内存块的 next 指针,指向下一个空闲内存块。
    • 这里将 block->next 指向当前的空闲链表头 pool->freeList
  4. pool->freeList = block

    • 将当前内存块 block 设置为新的空闲链表头。
    • 这样,每次循环都会将当前内存块插入到空闲链表的头部。

举例说明

假设 POOL_SIZE = 3BLOCK_SIZE = 64,内存池的内存布局如下:

内存池地址范围:0x1000 - 0x11C0 内存块 0:0x1000 - 0x1040 内存块 1:0x1040 - 0x1080 内存块 2:0x1080 - 0x10C0

第一次循环(i = 0):

  • block = (MemoryBlock*)(0x1000 + 0 * 64) = 0x1000
  • block->next = pool->freeList(初始时 pool->freeListNULL
  • pool->freeList = blockpool->freeList 现在指向 0x1000

空闲链表:0x1000 -> NULL

第二次循环(i = 1):

  • block = (MemoryBlock*)(0x1000 + 1 * 64) = 0x1040
  • block->next = pool->freeListpool->freeList 当前指向 0x1000
  • pool->freeList = blockpool->freeList 现在指向 0x1040

空闲链表:0x1040 -> 0x1000 -> NULL

第三次循环(i = 2):

  • block = (MemoryBlock*)(0x1000 + 2 * 64) = 0x1080
  • block->next = pool->freeListpool->freeList 当前指向 0x1040
  • pool->freeList = blockpool->freeList 现在指向 0x1080

空闲链表:0x1080 -> 0x1040 -> 0x1000 -> NULL


最终结果

经过循环后,空闲链表 pool->freeList 指向最后一个内存块 0x1080,链表的结构如下:

0x1080 -> 0x1040 -> 0x1000 -> NULL

这样,内存池中的所有内存块都被链接在一起,形成一个空闲链表。当需要分配内存时,可以从链表的头部取出一个内存块;当释放内存时,可以将内存块重新插入链表的头部。


为什么用链表?

使用链表的好处是:

  1. 高效分配和释放:从链表头部分配和释放内存块的时间复杂度是 O(1)。
  2. 动态管理:链表可以动态地管理空闲内存块,不需要额外的数据结构。

本文作者:Ryohei010

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!