核心知识点:内存管理、对齐、碎片整理、多线程安全。 升级方向: 支持不同大小的内存块(分级内存池),减少碎片; 实现内存对齐(如 8/16 字节对齐); 加锁保证多线程安全; 增加内存使用统计、泄漏检测等。
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <stdint.h>
#include <time.h>
// ===================== 配置常量 =====================
#define ALIGNMENT 16 // 内存对齐大小(16字节)
#define POOL_CLASSES 6 // 分级内存池的类别数
#define MAX_LEAK_CHECK_ITEMS 1024 // 泄漏检测最大记录数
// 分级内存池的块大小配置(按2的幂次递增,减少碎片)
static const size_t block_sizes[POOL_CLASSES] = {16, 32, 64, 128, 256, 512};
// ===================== 数据结构定义 =====================
/**
* 单个分级内存池结构(对应一种块大小)
*/
typedef struct SubPool {
size_t block_size; // 该子池的块大小(已对齐)
size_t block_count; // 总块数
size_t used_count; // 已使用块数
void* pool_start; // 内存池起始地址
void* free_list; // 空闲块链表头
pthread_mutex_t mutex; // 子池互斥锁(线程安全)
} SubPool;
/**
* 全局内存池管理器(整合所有分级子池)
*/
typedef struct MemPoolManager {
SubPool sub_pools[POOL_CLASSES]; // 分级子池数组
// 泄漏检测:记录分配的块(地址+分配时间+线程ID)
struct {
void* addr;
pthread_t tid;
time_t alloc_time;
} alloc_records[MAX_LEAK_CHECK_ITEMS];
int record_count; // 已记录的分配项数
pthread_mutex_t record_mutex; // 记录锁(保护alloc_records)
} MemPoolManager;
// ===================== 工具函数 =====================
/**
* 内存对齐计算(向上对齐到ALIGNMENT的整数倍)
*/
static inline size_t align_size(size_t size) {
return (size + ALIGNMENT - 1) & ~(ALIGNMENT - 1);
}
/**
* 查找匹配的子池(根据申请大小找最合适的分级子池)
*/
static int find_sub_pool(size_t size) {
for (int i = 0; i < POOL_CLASSES; i++) {
if (block_sizes[i] >= size) {
return i;
}
}
return -1; // 超过最大块大小,不支持
}
// ===================== 核心接口 =====================
/**
* 初始化内存池管理器
* @param manager 内存池管理器指针
* @param block_counts 每个分级子池的块数(数组长度=POOL_CLASSES)
* @return 0成功,-1失败
*/
int mem_pool_manager_init(MemPoolManager* manager, const size_t block_counts[POOL_CLASSES]) {
if (manager == NULL || block_counts == NULL) {
fprintf(stderr, "参数错误:空指针\n");
return -1;
}
// 初始化全局记录锁
if (pthread_mutex_init(&manager->record_mutex, NULL) != 0) {
fprintf(stderr, "记录锁初始化失败\n");
return -1;
}
manager->record_count = 0;
memset(manager->alloc_records, 0, sizeof(manager->alloc_records));
// 初始化每个分级子池
for (int i = 0; i < POOL_CLASSES; i++) {
SubPool* sub = &manager->sub_pools[i];
size_t block_size = align_size(block_sizes[i]); // 确保块大小对齐
size_t block_count = block_counts[i];
if (block_count == 0) {
fprintf(stderr, "子池%d块数不能为0\n", i);
return -1;
}
// 分配子池内存(总大小=块大小*块数)
size_t total_size = block_size * block_count;
sub->pool_start = malloc(total_size);
if (sub->pool_start == NULL) {
fprintf(stderr, "子池%d内存分配失败(需%zu字节)\n", i, total_size);
// 回滚已分配的子池
for (int j = 0; j < i; j++) {
free(manager->sub_pools[j].pool_start);
pthread_mutex_destroy(&manager->sub_pools[j].mutex);
}
return -1;
}
// 初始化子池属性
sub->block_size = block_size;
sub->block_count = block_count;
sub->used_count = 0;
sub->free_list = sub->pool_start;
// 初始化子池互斥锁
if (pthread_mutex_init(&sub->mutex, NULL) != 0) {
fprintf(stderr, "子池%d锁初始化失败\n", i);
free(sub->pool_start);
for (int j = 0; j < i; j++) {
free(manager->sub_pools[j].pool_start);
pthread_mutex_destroy(&manager->sub_pools[j].mutex);
}
return -1;
}
// 构建空闲链表
char* current = (char*)sub->pool_start;
for (size_t j = 0; j < block_count - 1; j++) {
void** next_ptr = (void**)current;
*next_ptr = current + block_size;
current += block_size;
}
*(void**)current = NULL; // 最后一块指向NULL
printf("子池%d初始化完成:块大小%zu字节,总块数%zu,总内存%zu字节\n",
i, block_size, block_count, total_size);
}
printf("内存池管理器初始化成功(共%d个分级子池)\n", POOL_CLASSES);
return 0;
}
/**
* 分配内存块
* @param manager 内存池管理器指针
* @param size 申请的内存大小
* @return 分配的内存地址(NULL表示失败)
*/
void* mem_pool_alloc(MemPoolManager* manager, size_t size) {
if (manager == NULL || size == 0) {
fprintf(stderr, "分配失败:参数错误\n");
return NULL;
}
// 找到匹配的子池
int pool_idx = find_sub_pool(size);
if (pool_idx == -1) {
fprintf(stderr, "分配失败:申请大小%zu超过最大块大小%zu\n", size, block_sizes[POOL_CLASSES-1]);
return NULL;
}
SubPool* sub = &manager->sub_pools[pool_idx];
void* alloc_block = NULL;
// 加锁保证线程安全
pthread_mutex_lock(&sub->mutex);
// 检查空闲链表是否有可用块
if (sub->free_list != NULL) {
// 取出空闲链表头
alloc_block = sub->free_list;
void* next_block = *(void**)sub->free_list;
sub->free_list = next_block;
sub->used_count++;
// 记录分配信息(用于泄漏检测)
pthread_mutex_lock(&manager->record_mutex);
if (manager->record_count < MAX_LEAK_CHECK_ITEMS) {
manager->alloc_records[manager->record_count].addr = alloc_block;
manager->alloc_records[manager->record_count].tid = pthread_self();
manager->alloc_records[manager->record_count].alloc_time = time(NULL);
manager->record_count++;
} else {
fprintf(stderr, "分配记录已满,无法记录新块%p\n", alloc_block);
}
pthread_mutex_unlock(&manager->record_mutex);
}
pthread_mutex_unlock(&sub->mutex);
if (alloc_block == NULL) {
fprintf(stderr, "子池%d无空闲块(申请大小%zu)\n", pool_idx, size);
} else {
printf("分配块:地址%p,子池%d,块大小%zu(申请大小%zu)\n",
alloc_block, pool_idx, sub->block_size, size);
}
return alloc_block;
}
/**
* 释放内存块
* @param manager 内存池管理器指针
* @param block 要释放的块地址
* @return 0成功,-1失败
*/
int mem_pool_free(MemPoolManager* manager, void* block) {
if (manager == NULL || block == NULL) {
fprintf(stderr, "释放失败:空指针\n");
return -1;
}
// 找到块所属的子池
int pool_idx = -1;
SubPool* sub = NULL;
for (int i = 0; i < POOL_CLASSES; i++) {
sub = &manager->sub_pools[i];
char* start = (char*)sub->pool_start;
char* end = start + sub->block_size * sub->block_count;
if ((char*)block >= start && (char*)block < end) {
pool_idx = i;
break;
}
}
if (pool_idx == -1) {
fprintf(stderr, "释放失败:地址%p不在内存池范围内\n", block);
return -1;
}
// 检查是否是合法的块起始地址
size_t offset = (char*)block - (char*)sub->pool_start;
if (offset % sub->block_size != 0) {
fprintf(stderr, "释放失败:地址%p不是合法块起始地址\n", block);
return -1;
}
// 加锁释放
pthread_mutex_lock(&sub->mutex);
// 将块插回空闲链表头
*(void**)block = sub->free_list;
sub->free_list = block;
sub->used_count--;
// 移除分配记录
pthread_mutex_lock(&manager->record_mutex);
for (int i = 0; i < manager->record_count; i++) {
if (manager->alloc_records[i].addr == block) {
// 覆盖当前记录(简单实现,有序场景可优化)
memmove(&manager->alloc_records[i], &manager->alloc_records[i+1],
(manager->record_count - i - 1) * sizeof(manager->alloc_records[0]));
manager->record_count--;
break;
}
}
pthread_mutex_unlock(&manager->record_mutex);
pthread_mutex_unlock(&sub->mutex);
printf("释放块:地址%p,子池%d,块大小%zu\n", block, pool_idx, sub->block_size);
return 0;
}
/**
* 检测内存泄漏
* @param manager 内存池管理器指针
*/
void mem_pool_check_leak(const MemPoolManager* manager) {
if (manager == NULL) {
fprintf(stderr, "泄漏检测失败:内存池未初始化\n");
return;
}
pthread_mutex_lock((pthread_mutex_t*)&manager->record_mutex); // 去掉const(仅检测)
printf("\n===== 内存泄漏检测报告 =====\n");
if (manager->record_count == 0) {
printf("未检测到内存泄漏\n");
} else {
printf("检测到%d个未释放的内存块:\n", manager->record_count);
for (int i = 0; i < manager->record_count; i++) {
struct tm* tm = localtime(&manager->alloc_records[i].alloc_time);
char time_str[64];
strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", tm);
printf(" 块地址:%p,分配线程ID:%lu,分配时间:%s\n",
manager->alloc_records[i].addr,
(unsigned long)manager->alloc_records[i].tid,
time_str);
}
}
printf("=============================\n");
pthread_mutex_unlock((pthread_mutex_t*)&manager->record_mutex);
}
/**
* 打印内存池状态(使用统计)
* @param manager 内存池管理器指针
*/
void mem_pool_print_status(const MemPoolManager* manager) {
if (manager == NULL) {
printf("内存池未初始化\n");
return;
}
printf("\n===== 内存池整体状态 =====\n");
size_t total_blocks = 0, total_used = 0, total_free = 0;
size_t total_memory = 0, used_memory = 0, free_memory = 0;
for (int i = 0; i < POOL_CLASSES; i++) {
const SubPool* sub = &manager->sub_pools[i];
size_t free_blocks = sub->block_count - sub->used_count;
total_blocks += sub->block_count;
total_used += sub->used_count;
total_free += free_blocks;
total_memory += sub->block_size * sub->block_count;
used_memory += sub->block_size * sub->used_count;
free_memory += sub->block_size * free_blocks;
printf("子池%d:块大小%zu字节,总块数%zu,已使用%zu,空闲%zu\n",
i, sub->block_size, sub->block_count, sub->used_count, free_blocks);
}
printf("=============================\n");
printf("总块数:%zu,已使用:%zu,空闲:%zu\n", total_blocks, total_used, total_free);
printf("总内存:%zu字节,已使用:%zu字节,空闲:%zu字节\n",
total_memory, used_memory, free_memory);
printf("=============================\n\n");
}
/**
* 销毁内存池管理器
* @param manager 内存池管理器指针
*/
void mem_pool_manager_destroy(MemPoolManager* manager) {
if (manager == NULL) {
return;
}
// 销毁每个子池
for (int i = 0; i < POOL_CLASSES; i++) {
SubPool* sub = &manager->sub_pools[i];
if (sub->pool_start != NULL) {
free(sub->pool_start);
sub->pool_start = NULL;
}
pthread_mutex_destroy(&sub->mutex);
memset(sub, 0, sizeof(SubPool));
}
// 销毁记录锁
pthread_mutex_destroy(&manager->record_mutex);
memset(manager, 0, sizeof(MemPoolManager));
printf("内存池管理器已销毁\n");
}
// ===================== 测试代码 =====================
// 线程函数:模拟多线程分配/释放
void* thread_func(void* arg) {
MemPoolManager* manager = (MemPoolManager*)arg;
void* blocks[5];
// 分配5个块(随机大小)
for (int i = 0; i < 5; i++) {
size_t size = rand() % 500 + 1; // 1~500字节
blocks[i] = mem_pool_alloc(manager, size);
if (blocks[i] == NULL) {
fprintf(stderr, "线程%lu分配块%d失败\n", (unsigned long)pthread_self(), i);
}
}
// 释放前3个块
for (int i = 0; i < 3; i++) {
if (blocks[i] != NULL) {
mem_pool_free(manager, blocks[i]);
}
}
// 故意保留2个块不释放(模拟泄漏)
return NULL;
}
int main(void) {
// 1. 初始化内存池(每个子池的块数配置)
size_t block_counts[POOL_CLASSES] = {10, 10, 10, 10, 10, 10}; // 每个子池10个块
MemPoolManager manager;
if (mem_pool_manager_init(&manager, block_counts) != 0) {
fprintf(stderr, "内存池初始化失败\n");
return -1;
}
// 2. 打印初始状态
mem_pool_print_status(&manager);
// 3. 多线程测试(创建3个线程)
pthread_t t1, t2, t3;
pthread_create(&t1, NULL, thread_func, &manager);
pthread_create(&t2, NULL, thread_func, &manager);
pthread_create(&t3, NULL, thread_func, &manager);
// 等待线程结束
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_join(t3, NULL);
// 4. 打印线程执行后的状态
mem_pool_print_status(&manager);
// 5. 检测内存泄漏(预期6个未释放块)
mem_pool_check_leak(&manager);
// 6. 销毁内存池
mem_pool_manager_destroy(&manager);
return 0;
}