c-内存池实现

为什么要使用内存池

  1. 避免反复申请和释放内存时出现的内存碎片;
  2. 防止内存泄漏;
  3. 提高申请和释放内存的效率。

结构

01

代码

  • mempool.h
#ifndef MEMPOOL_H__
#define MEMPOOL_H__

#include <stdio.h>

#define MEMP_ALIGNMENT  32
#define MEMP_PAGE_SIZE 4096
#define MEMP_MAX_ALLOC_FROM_POOL (MEMP_PAGE_SIZE-1)

// memp_align_ptr 用来寻找指针对齐后的位置。
#define memp_align_ptr(p, alignment) \
    (void *)((((size_t)p) + (alignment - 1)) & ~(alignment - 1))

typedef struct memp_large_st{
    struct memp_large_st *next;
    void *alloc;
}memp_large;

typedef struct memp_node_st{

    struct memp_node_st *next;

    unsigned char *last;
    unsigned char *end;

}memp_node;

typedef struct memp_pool_st{

    size_t max;
    memp_node *current;
    memp_large *large;

    memp_node head[0];	// 柔性数组,只是一个标志,并步占用空间。

}memp_pool;

memp_pool *memp_create_pool(size_t size);	// size 为大小内存的分界点,小于 size 的内存认为是小块,其余大小认为是大块。
void memp_destory_pool(memp_pool *pool);

void *memp_alloc(memp_pool *pool, size_t size);
void *memp_malloc(memp_pool *pool, size_t size);
void *memp_calloc(memp_pool *pool, size_t nitems, size_t size);	// 多了初始化为 0 这一操作

void memp_free(memp_pool *pool, void *ptr);	// 释放大块内存。
void memp_reset_pool(memp_pool *pool);	// 释放内存池中的所有内存,除了申请的大块内存,其他内存并不是真正的释放,只是指针的移动。

#endif
  • mempool.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "./mempool.h"

memp_pool *memp_create_pool(size_t size){

    memp_pool *pool = NULL;
    int res;

    res = posix_memalign((void**)&pool, MEMP_ALIGNMENT, size+sizeof(*pool)+sizeof(memp_node));
    if(res){
        perror("posix_memalign()");
        return NULL;
    }

    pool->max = size < MEMP_MAX_ALLOC_FROM_POOL ? size : MEMP_MAX_ALLOC_FROM_POOL;
    pool->current = pool->head;
    pool->large = NULL;
    
    pool->head->last = (unsigned char*)pool + sizeof(memp_pool) + sizeof(memp_node);
    pool->head->end = pool->head->last + size;

    return pool;
}

void memp_destory_pool(memp_pool *pool){

    memp_large *l;
    memp_node *cur, *n;

    for(l = pool->large; l; l = l->next){
        if(l->alloc != NULL){
            puts("free a large");
            free(l->alloc);
        }
    }

    cur = pool->head->next;
    while(cur != NULL){
        n = cur->next;
        puts("free a block");
        free(cur);
        cur = n;
    }
 
    puts("free pool");
    free(pool);

    return ;
}
void *memp_alloc_large(memp_pool *pool, size_t size){
    
    void *p = malloc(size);
    if(p == NULL){
        return NULL;
    }

    memp_large *large;
    
    for(large = pool->large; large != NULL; large = large->next){
        if(large->alloc == NULL){
            large->alloc = p;
            return p;
        }
    }

    large = memp_alloc(pool, sizeof(memp_large));
    if(large == NULL){
        free(p);
        return NULL;
    }

    large->alloc = p;
    large->next = pool->large;
    pool->large = large;

    return p;
}

void *memp_alloc_block(memp_pool *pool, size_t size){

    unsigned char *res = NULL;
    memp_node *head = pool->head;
    size_t alloc_size = (size_t)(head->end - (unsigned char*)head);
    memp_node *new_node, *cur, *p;

    int ret = 0;

    ret = posix_memalign((void**)&res, MEMP_ALIGNMENT, alloc_size);
    if(ret){
        perror("posix_memalign()");
        return NULL;
    }

    new_node = (memp_node*)res;
    new_node->end = res + alloc_size;
    new_node->next = NULL;

    res += sizeof(memp_node);
    res = memp_align_ptr(res, MEMP_ALIGNMENT);
    new_node->last = res + size;

    cur = pool->current;

    for(p = cur; p->next != NULL; p = p->next){
        ;
    }

    p->next = new_node;

    // pool->current = cur != NULL ? cur : new_node;

    return res;
}

void *memp_alloc(memp_pool *pool, size_t size){

    unsigned char *res = NULL;
    memp_node *p = NULL;

    if(size <= pool->max){

        p = pool->current;

        do{

            res = memp_align_ptr(p->last, MEMP_ALIGNMENT);
            if((size_t)(p->end - res) >= size){
                p->last = res + size;
                return res;
            }
            p = p->next;

        }while(p != NULL);

        return memp_alloc_block(pool, size);

    }

    return memp_alloc_large(pool, size);

}
void *memp_malloc(memp_pool *pool, size_t size){

    unsigned char *res = NULL;
    memp_node *p = NULL;

    if(size <= pool->max){

        p = pool->current;

        do{

            res = memp_align_ptr(p->last, MEMP_ALIGNMENT);
            if((size_t)(p->end - res) >= size){
                p->last = res + size;
                return res;
            }
            p = p->next;

        }while(p != NULL);

        return memp_alloc_block(pool, size);

    }

    return memp_alloc_large(pool, size);
}
void *memp_calloc(memp_pool *pool, size_t nitems, size_t size){

    size_t size_true = nitems * size;

    void *res = memp_alloc(pool, size_true);
    if(res != NULL){
        memset(res, 0, size_true);
    }

    return res;
}

void memp_free(memp_pool *pool, void *ptr){

    memp_large *large;

    for(large = pool->large; large != NULL; large = large->next){
        if(large->alloc == ptr){
            free(large->alloc);
            large->alloc = NULL;

            break;
        }
    }

    return ;
}

void memp_reset_pool(memp_pool *pool){

    memp_node *head;
    memp_large *large;

    for(large = pool->large; large != NULL; large = large->next){
        if(large->alloc != NULL){
            free(large->alloc);
        }
    }
    pool->large = NULL;

    for(head = pool->head; head != NULL; head = head->next){
        head->last = (unsigned char*)head + sizeof(memp_node);
    }

    return ;
}
  • test.c
#include <stdio.h>
#include <stdlib.h>

#include "./mempool.h"

int main(){

    puts("hello world");

    memp_pool *pool = NULL;
    size_t size = 1 << 12; // 4096
    
    pool = memp_create_pool(size);
    
    char *ptr = NULL;

    ptr = memp_alloc(pool, 1 << 13);
    memp_free(pool, ptr);
    ptr = memp_alloc(pool, 1 << 13);
    memp_free(pool, ptr);
    ptr = memp_alloc(pool, 1 << 13);
    memp_free(pool, ptr);
    ptr = memp_alloc(pool, 1 << 13);
    fflush(stdout);

    for(int i = 0; i < 10; i++){
        ptr = memp_alloc(pool, 1 << 10);
    }

    for(int i = 0; i < 10; i++){
        
        ptr = memp_malloc(pool, 1 << 11);

    }

    for(int i = 0; i < 10; i++){

        ptr = memp_calloc(pool, 32, sizeof(long));

    }

    memp_destory_pool(pool);

    exit(0);
}

待完善点

  • 小块内存的重复使用:目前代码并没有释放小块内存的功能。可以等某一块中的所有小块内存都不使用时,直接释放这一大块内存。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
内存池是一种常见的内存管理技术,它可以在程序启动时预先分配一定数量的内存空间,并将其划分为多个固定大小的块,然后在程序运行过程中动态地将这些块分配给需要使用内存的对象,从而减少内存碎片和内存分配的时间开销。下面是一个简单的内存池实现示例: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #define BLOCK_SIZE 1024 #define BLOCK_NUM 10 typedef struct _memory_block { void *start; void *end; struct _memory_block *next; } memory_block; typedef struct _memory_pool { size_t block_size; memory_block *free_list; memory_block *used_list; } memory_pool; memory_pool *memory_pool_create(size_t block_size) { memory_pool *pool = (memory_pool *) malloc(sizeof(memory_pool)); pool->block_size = block_size; pool->free_list = NULL; pool->used_list = NULL; for (int i = 0; i < BLOCK_NUM; i++) { memory_block *block = (memory_block *) malloc(sizeof(memory_block)); block->start = malloc(block_size); block->end = (char *) block->start + block_size; block->next = pool->free_list; pool->free_list = block; } return pool; } void *memory_pool_alloc(memory_pool *pool, size_t size) { memory_block *block = pool->free_list; while (block) { if ((char *) block->end - (char *) block->start >= size) { void *ptr = block->start; block->start = (char *) block->start + size; if (block->start == block->end) { pool->free_list = block->next; block->next = pool->used_list; pool->used_list = block; } return ptr; } block = block->next; } return NULL; } void memory_pool_free(memory_pool *pool) { memory_block *block = pool->used_list; while (block) { memory_block *next = block->next; free(block->start); free(block); block = next; } block = pool->free_list; while (block) { memory_block *next = block->next; free(block->start); free(block); block = next; } free(pool); } int main() { memory_pool *pool = memory_pool_create(BLOCK_SIZE); char *str1 = (char *) memory_pool_alloc(pool, 10); char *str2 = (char *) memory_pool_alloc(pool, 20); char *str3 = (char *) memory_pool_alloc(pool, 30); strcpy(str1, "hello"); strcpy(str2, "world"); strcpy(str3, "memory pool"); printf("%s %s %s\n", str1, str2, str3); memory_pool_free(pool); return 0; } ``` 该示例中,首先定义了两个结构体:memory_block表示内存块,包括起始地址、结束地址和下一个内存块的指针;memory_pool表示内存池,包括块大小、空闲链表和已用链表。 然后,定义了三个函数:memory_pool_create用于创建内存池,先分配一定数量的内存块,并将其加入空闲链表;memory_pool_alloc用于从内存池中分配一块指定大小的内存空间,遍历空闲链表,找到第一个大小足够的内存块,并将其划分为新的内存空间;memory_pool_free用于释放内存池中的所有内存块,将已用链表和空闲链表中的内存块全部释放。 最后,在main函数中创建一个内存池,并使用memory_pool_alloc从内存池中分配三个字符串空间,将其赋值并打印出来,最后使用memory_pool_free释放内存池中的所有内存块。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值