搭建内存池2.0

搭建内存池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();

}
}



相关推荐
weixin_456808383 小时前
【沁恒蓝牙开发】关闭独立看门狗
c语言·单片机·嵌入式硬件
weixin_456808383 小时前
【沁恒蓝牙开发】拓展广播 Code PHY-从机
c语言·嵌入式硬件
计算机安禾3 小时前
【数据结构与算法】第16篇:串(String)的定长顺序存储与朴素模式匹配
c语言·数据结构·c++·学习·算法·visual studio code·visual studio
AI科技星3 小时前
基于v≡c公设的理论优化方案
c语言·开发语言·算法·机器学习·数据挖掘
自然常数e4 小时前
预处理讲解
java·linux·c语言·前端·visual studio
jllllyuz4 小时前
小型物联网系统——家居网关设计(C语言实现)
c语言·物联网·struts
daxi1504 小时前
C语言从入门到进阶——第17讲:字符串函数
c语言·开发语言·算法·蓝桥杯
wljy14 小时前
第十四届蓝桥杯大赛软件赛省赛C/C++ 大学 B 组(个人见解,已完结)
c语言·c++·算法·蓝桥杯
程序员zgh4 小时前
C++ 环形队列 从原理到实例演示
c语言·开发语言·数据结构·c++·学习