搭建内存池2.0
在上一篇中实现了搭建了一个内存池,详情请看这篇文章C语言进阶项目------搭建内存池但是里边有些瑕疵,在后面我有尝试修改,但是realloc总是会报错,是因为指针处理的问题,指针混论然后还有野指针,后来反复问AI修改,改的不能运行了。所以我又重新写了便,这次为了避免指针的问题,我采用了双指针的写法。至少在我这里所有功能基本都实现了,可能会有一些边界处理没有考虑到的。但总归是一个完整的项目了
思路就参考上一篇,都是一样的。但是这次为了彻底杜绝指针带来的问题,也没有选择留有将内存块摘出的操作,而是在块的结构体中加了一个use变量来确定这个块是不是空闲块,这样一来不管是否使用都在一个链表上。这样的好处是,做合并操作就没有复杂的指针了。
而且吸取了上一次的教训,这一次的函数我写的功能更为单一和精简,在realloc功能中也得到了复用,下面就是我的实现和我的测试结果
c
#define _CRT_SECURE_NO_WARNINGS // vs编译器需要加
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<stdbool.h>
#define POOL_SIZE 2048
//创建内存池
char memory_pool[POOL_SIZE];
//定义内存块结构
typedef struct block {
bool use;
size_t size;
struct block* next;
struct block* pre;
}block;
//定义内存块链表结构
typedef struct free_blocks_list {
size_t size; //内存池可用空间
int block_num; //空闲块数量
block* head; //内存块链表头节点
}free_block_list;
//初始化内存块链表指针
free_block_list* block_list = NULL;
//初始化内存块链表
void init() {
block_list = (free_block_list*)memory_pool;
//可用空间大小要减去表头
block_list->size = POOL_SIZE - sizeof(free_block_list);
block_list->block_num = 1;
// 初始化链表头
block_list->head = (block*)(memory_pool + sizeof(free_block_list));
// 减去块头为可用空间
block_list->head->size = block_list->size - sizeof(block);
block_list->head->next = NULL;
block_list->head->pre = NULL;
block_list->head->use = 0;
}
block* splite(block* big_block, size_t size) {
//初始化分裂块
block* post_block_after_splite = (block*)((char*)big_block + sizeof(block) + size);
//初始化后块
post_block_after_splite->next = big_block->next;
post_block_after_splite->pre = big_block;
post_block_after_splite->use = 0;
post_block_after_splite->size = big_block->size - size - sizeof(block);
//修改前块数据
big_block->next = post_block_after_splite;
big_block->size = size;
//修改内存块链表数据
block_list->block_num++;
block_list->size -= sizeof(block);
//返回原指针
return big_block;
}
block* find_block(size_t size) {
// 从链表头开始遍历
block* temp_ptr = block_list->head;
while (temp_ptr) {
if (temp_ptr->size >= size && temp_ptr->use == 0) break;
temp_ptr = temp_ptr->next;
}
// 没有找到合适的块
if (temp_ptr == NULL) return NULL;
// 找到合适的块
else if (temp_ptr->size <= size + sizeof(block)) return temp_ptr;
// 找到过大的块
else return splite(temp_ptr, size);
}
void* get_memory(size_t size) {
if (size <= 0 || size > block_list->size) {
printf("申请空间大小不符合内存空间!");
return NULL;
}
// 寻找合适的内存块
block *suitable_block = find_block(size);
// 没找到合适的块
if (!suitable_block) {
printf("内存池碎片过多,已经没有合适的块,请执行合并操作!");
return NULL;
}
// 找到合适的块
else {
suitable_block->use = 1;
//只返回数据区;
return (char*)suitable_block + sizeof(block);
}
}
bool merge(block* free_block) {
block* free_block_pre = free_block->pre;
block* free_block_post = free_block->next;
// 向前合并
if (free_block_pre && free_block->pre->use == 0) {
// 改变相邻块指针指向
free_block_pre->next = free_block->next;
free_block->next->pre = free_block_pre;
// 合并块
free_block_pre->size += sizeof(block) + free_block->size;
// 修改内存块链表信息
block_list->block_num--;
block_list->size += sizeof(block);
return 1;
}
// 向后合并
else if(free_block_post && free_block_post->use == 0) {
// 改变相邻块指针指向
free_block->next = free_block_post->next;
// 如果后面没有块不需要修改
if(free_block_post->next) free_block_post->next->pre = free_block;
// 合并块
free_block->size += sizeof(block) + free_block_post->size;
// 修改内存块链表信息
block_list->block_num--;
block_list->size += sizeof(block);
return 1;
}
return 0;
}
void free_memory(void* data_area) {
// 找到块头
block* block_addr = (block*)((char*)data_area - sizeof(block));
// 块回收
block_addr->use = 0;
// 更新块表信息
block_list->block_num--;
block_list->size += block_addr->size;
merge(block_addr);
}
void show_pool_and_block_list() {
printf("--------------内-存-信-息---------------\n");
printf("|物理内存总容量:%d\n", POOL_SIZE);
printf("---------------------------------------\n");
printf("|实际可用总容量为:%d\n", POOL_SIZE - sizeof(free_block_list) - sizeof(block));
printf("---------------------------------------\n");
printf("|当前可用容量为:%d\n", block_list->size);
printf("---------------------------------------\n");
printf("|sizeof(block) = %ld, sizeof(block_list) = %ld\n", sizeof(block), sizeof(block_list));
printf("---------------------------------------\n");
printf("|当前链表中的块数为:%d\n", block_list->block_num);
printf("|head->");
block* t = block_list->head;
while (t) {
printf("\n|\t块地址:[%p] ~ [%p] ,内存块大小(块头 + 数据区):%zu (%zu + %d) ,使用情况: %d",
t, (char*)t + t->size + sizeof(block), t->size + sizeof(block), sizeof(block) , t->size, t->use);
t = t->next;
}
printf("\n");
printf("--------------------------------------\n");
}
void* get_memory_and_init(size_t size) {
char* res = (char*)malloc(sizeof(char) * size);
if (res == NULL) {
printf("初始化失败!\n");
return res;
}
memset(res, 0, size);
return res;
}
void* my_realloc(void* ptr, size_t new_size) {
if (ptr == NULL) return NULL;
// 找到块头
block* current_block = (block*)((char*)ptr - sizeof(block));
// 相等情况
if (new_size == current_block->size) {
return ptr;
}
// 缩容操作
else if (new_size < current_block->size) {
splite(current_block, new_size);
// 修改链表块
block_list->size += current_block->next->size;
block_list->block_num++;
return (char*)current_block + sizeof(block);
}
//扩容操作
else {
//先执行合并,合并后内存满足
if (merge(current_block) && current_block->size >= new_size) {
// 合并成功
// 当前块的容量满足 申请 + 块头的空间 则分裂
if (current_block->size > new_size + sizeof(block)) current_block = splite(current_block, new_size);
// 修改块内数据
current_block->use = 1;
// 修改内存块链表数据
block_list->block_num--;
block_list->size -= current_block->size;
return (char*)current_block + sizeof(block);
}
// 寻找合适的块
else {
block* suitable_block = find_block(new_size);
// 没有找到直接return结束
if (!suitable_block) return NULL;
// 找到后数据搬运
strcpy((char*)suitable_block + sizeof(block), (char*)ptr);
// 释放当前块
free_memory(current_block);
// 修改内存块链表数据
block_list->size -= suitable_block->size;
block_list->block_num--;
// 调出内存块
suitable_block->use = 1;
return (char*)suitable_block + sizeof(block);
}
}
}
int main() {
init();
int* arr = (int*)get_memory(sizeof(int) * 4);
int* arr1 = (int*)get_memory(sizeof(int) * 40);
int* arr2 = (int*)get_memory(sizeof(int) * 40);
int* arr3 = (int*)get_memory(sizeof(int) * 200);
int* arr4 = (int*)get_memory(sizeof(int) * 40);
int* arr5 = (int*)get_memory(sizeof(int) * 100);
show_pool_and_block_list();
printf("******************************************************************************************************************************\n");
free_memory(arr);
free_memory(arr1);
free_memory(arr2);
free_memory(arr3);
free_memory(arr4);
show_pool_and_block_list();
printf("******************************************************************************************************************************\n");
int* arr6 = (int*)get_memory(sizeof(int) * 90); //392
show_pool_and_block_list();
printf("******************************************************************************************************************************\n");
arr6 = (int*)my_realloc(arr6 ,sizeof(int) * 200);
show_pool_and_block_list();
printf("******************************************************************************************************************************\n");
arr6 = (int*)my_realloc(arr6, sizeof(int) * 20);
show_pool_and_block_list();
}
}


