内存池(Memory Pool)
内存池(Memory Pool)是一种内存管理技术,主要用于优化程序中动态内存分配和释放的效率,减少内存碎片,提高程序运行速度。以下是内存池的一些关键概念和工作原理介绍;
一、基本概念
内存池预先从操作系统申请一大块连续内存空间,并将其管理起来,当程序需要分配内存时,不再直接向操作系统请求,而是从内存池中快速分配一小块事先准备好的内存单元。当不再需要这些内存时,也不是直接归还给操作系统,而是归还给内存池,由内存池统一管理,适时或在程序结束时再归还给操作系统。
二、工作原理
预分配: 程序启动或初始化阶段,一次性向系统申请大量内存,形成内存池。
分割管理: 内存池中的内存会被分割成多个大小相等或不等的块(固定大小或可变大小内存池)。
分配: 当程序请求内存时,内存池快速分配一个合适的内存块给请求方,这个过程往往通过链表、位图等数据结构高效实现。
回收: 释放内存时,不是直接还给系统,而是归还给内存池,可能需要进行合并相邻空闲块的操作以减少碎片。
重用: 回收的内存块可以被后续的分配请求重用,减少了频繁的系统调用,提高了效率。
三、优缺点点
优点
- 提高效率: 减少了系统调用的次数,内存分配和释放更快。
- 减少碎片: 通过管理内存分配策略,可以有效减少内存碎片问题。
- 可控性: 程序员可以更好地控制内存的使用,有利于内存泄漏的检测和防止。
- 性能提升: 对于频繁分配和释放小块内存的场景尤其有效,如游戏、数据库、服务器等高性能应用。
缺点
- 内存占用: 初始时预分配的内存可能会造成一定的内存浪费。
- 实现复杂: 内存池的设计和实现相对复杂,需要考虑多种因素,如内存分配策略、内存碎片整理等。
- 调试困难: 错误的内存管理可能会导致难以追踪的bug。
四、简单实现
- 实现每次固定申请内存块的大小,每次内存可申请和释放
#include <stdio.h>
#include <stdlib.h>
#include <string.h>#define MEM_POOL_SIZE 4096
typedef struct mempool_s {int block_size; // 每个内存块的大小int free_count; // 空闲内存块的数量char* free_ptr; // 指向第一个空闲内存块的指针char* mem_ptr; // 指向第一个内存块的指针
} mempool_t;int mempool_init(mempool_t* pool, int block_size)
{// 初始化内存池if (pool == NULL)return -1;if (block_size <= 16) block_size = 16;pool->block_size = block_size;pool->mem_ptr = (char*)malloc(MEM_POOL_SIZE);if (pool->mem_ptr == NULL)return -1;pool->free_ptr = pool->mem_ptr;pool->free_count = MEM_POOL_SIZE / block_size;// 初始化内存池中的内存块char* ptr = pool->free_ptr;for (int i = 0; i < pool->free_count; i++){//将当前内存块的首地址处存储下一个内存块的地址,通过 (char**)ptr 强制类型转换,//将 ptr 转为指向 char* 类型的指针的指针,然后将 ptr + block_size 的值存入,形成一个单向链表结构。*(char**)ptr = ptr + block_size; // 下一个内存块的指针ptr += block_size; // 移动当前内存块的指针 ptr 到下一个内存块的起始位置,即加上 block_size}*(char**)ptr = NULL; // 最后一个内存块的下一个地址设为 NULL,表示链表的结束return 0;
}void* mempool_alloc(mempool_t* pool)
{// 分配一个内存块if (pool == NULL || pool->free_count <= 0)return NULL;void* ptr = pool->free_ptr;pool->free_ptr = *(char**)ptr;pool->free_count--;return ptr;
}void mempool_dest(mempool_t* pool)
{// 销毁内存池if (pool == NULL || pool->mem_ptr == NULL)return;free(pool->mem_ptr);
}void mempool_free(mempool_t* pool, void* ptr)
{// 释放一个内存块if (pool == NULL || ptr == NULL)return;//头插法*(char**)ptr = pool->free_ptr;pool->free_ptr = (char*)ptr;pool->free_count++;
}int main()
{// 初始化内存池mempool_t pool;mempool_init(&pool, 16);
// 分配内存块void* ptr1 = mempool_alloc(&pool);memcpy(ptr1, "Hello, world!", 13);printf("ptr1 : %p,---%s\n", ptr1, (char*)ptr1);void* ptr2 = mempool_alloc(&pool);memcpy(ptr2, "你好!", 6);printf("ptr2 : %p,---%s\n", ptr2, (char*)ptr2);void* ptr3 = mempool_alloc(&pool);memcpy(ptr3, "再见", 6);printf("ptr3 : %p,---%s\n", ptr3, (char*)ptr3);// 释放内存块mempool_free(&pool, ptr1);void* ptr4 = mempool_alloc(&pool);printf("ptr4 : %p,---%s\n", ptr4, (char*)ptr4);// 再次释放内存块mempool_free(&pool, ptr2);void* ptr5 = mempool_alloc(&pool);printf("ptr5 : %p,---%s\n", ptr5, (char*)ptr5);// 销毁内存池mempool_dest(&pool);return 0;
}
- 不固定内存大小,没有释放每次申请的空间,只有最有一个全部释放
#include <stdio.h>
#include <stdlib.h>
#include <string.h>typedef struct mompool_node {char * free_ptr; // 指向内存池中空闲的内存char * end_ptr; // 指向内存池的结束位置struct mompool_node * next; // 指向下一个内存池节点
} mompool_node_t;typedef struct mompool {struct mompool_node * head; // 指向内存池链表的头部struct mompool_node * current; // 指向内存池链表的尾部int size; // 内存池页大小
} mompool_t;int mompool_init(mompool_t * pool, int page_size) {// 初始化内存池if (pool == NULL)return -1;void * ptr = malloc(page_size);mompool_node_t *node = (mompool_node_t*)ptr;// node节点占用申请的内存空间node->free_ptr = (char*)ptr + sizeof(mompool_node_t);node->end_ptr = (char*)ptr + page_size;node->next = NULL;pool->head = node;;pool->current = node;pool->size = page_size;;return 0;
}void * mompool_alloc(mompool_t * pool, int size) {// 从内存池中分配内存if (pool == NULL || size <= 0) return NULL;mompool_node_t* node = (mompool_node_t*)pool->current;do {if (node->end_ptr - node->free_ptr >= size) {char* ptr = node->free_ptr;node->free_ptr += size;return ptr;}node = node->next;} while (node);void * ptr = malloc(pool->size);node = (mompool_node_t*)ptr;node->free_ptr = (char*)ptr + sizeof(mompool_node_t);node->end_ptr = (char*)ptr + pool->size;// 头插法,加入内存池链表中node->next = pool->current;;pool->current = node;// 分配内存char* ret_ptr = node->free_ptr;node->free_ptr += size;return ret_ptr;
}void mompool_destroy(mompool_t * pool) {// 销毁内存池if (pool == NULL) return;while (pool->head != NULL) {void * ptr = pool->head;mompool_node_t* node = (mompool_node_t*)ptr;pool->head = node->next;free(ptr);}return;
}void mompool_free(mompool_t * pool, void * ptr) {// 将内存归还到内存池中
}int main() {mompool_t mompool;mompool_init(&mompool, 4096);// 使用内存池分配内存void * ptr1 = mompool_alloc(&mompool, 16);// 内存越界memcpy(ptr1, "12345678901234567890", 20);printf("ptr1 : %p,---%s\n", ptr1, (char*)ptr1);void * ptr2 = mompool_alloc(&mompool, 32);memcpy(ptr2, "qwertyuiopasdfghjklzxcvbnmqwertyuiop", 36);printf("ptr2 : %p,---%s\n", ptr2, (char*)ptr2);printf("ptr1 : %p,---%s\n", ptr1, (char*)ptr1);memcpy(ptr1, "09876543210987654321", 20);printf("ptr1 : %p,---%s\n", ptr1, (char*)ptr1);// sprintf(buffer, "%d", char),内有检测目标字符数组的大小,肯可能会出现内存越界的情况mompool_destroy(&mompool);return 0;
}
专属学习链接:https://xxetb.xetslk.com/s/36yiy3