仿nginx内存池的实现

头文件:mem_palloc.h

#ifndef _MEM_PALLOC_H_INCLUDED_
#define _MEM_PALLOC_H_INCLUDED_

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <malloc.h>
#include <stdint.h>

typedef unsigned char u_char;
typedef intptr_t        mem_int_t;
typedef uintptr_t       mem_uint_t;
typedef intptr_t        mem_flag_t;

typedef void (*mem_pool_cleanup_pt)(void *data);
typedef struct mem_pool_s        mem_pool_t;
typedef struct mem_pool_large_s  mem_pool_large_t;
typedef struct mem_pool_cleanup_s  mem_pool_cleanup_t;

/********************************************************
*             global var
* *****************************************************/
mem_uint_t  mem_pagesize;

#ifndef MEX_ALIGNMENT
#define MEM_ALIGNMENT   sizeof(unsigned long)    /* platform word */
#endif

#define mem_free          free

#define MEM_MAX_ALLOC_FROM_POOL  (mem_pagesize - 1)

#define MEM_DEFAULT_POOL_SIZE    (16 * 1024)

#define MEM_POOL_ALIGNMENT       16
#define MEM_MIN_POOL_SIZE                                                     \
    mem_align((sizeof(mem_pool_t) + 2 * sizeof(mem_pool_large_t)),            \
              MEM_POOL_ALIGNMENT)

#define mem_align(d, a)     (((d) + (a - 1)) & ~(a - 1))
#define mem_align_ptr(p, a)                                                   \
    (u_char *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1))

/*****************************************************************/
typedef struct {
    u_char               *last;   //当前内存池分配到此处,即下一次分配从此处开始
    u_char               *end;    //内存池的结束位置
    mem_pool_t           *next;   //内存池可以有很多块内存,这些内存块链表指针
    mem_uint_t            failed; //分配失败次数
} mem_pool_data_t;

struct mem_pool_s {
    mem_pool_data_t       d;    //内存池数据块
    size_t                max;  //内存池数据块的最大值   
    mem_pool_t           *current; //当前内存池的地址
    mem_pool_large_t     *large;   //大块内存链表
    mem_pool_cleanup_t   *cleanup; //释放内存池的回调
};

struct mem_pool_large_s {
    mem_pool_large_t     *next; //大块内存链表指针
    void                 *alloc; //大块内存申请到的地址
};

struct mem_pool_cleanup_s {
    mem_pool_cleanup_pt   handler;
    void                 *data;
    mem_pool_cleanup_t   *next;
};

void *mem_alloc(size_t size);    //为大块内存申请内存

void *mem_palloc(mem_pool_t *pool, size_t size);    //从内存池申请内存

void *mem_memalign(size_t alignment, size_t size);  //分配对齐的内存

mem_pool_t *mem_create_pool(size_t size);     //创建内存池

void mem_destroy_pool(mem_pool_t *pool);      //释放内存池

#endif  /*_MEM_PALLOC_H_INCLUDED_*/

内存池接口实现c文件:mem_palloc.c

#include "mem_palloc.h"

void mem_os_init(void)
{
    mem_pagesize = getpagesize();  //获取pagesize到全局变量mem_pagesize
}

void *mem_alloc(size_t size)
{
    void *p;

    p = malloc(size);
    if (p == NULL) {
        fprintf(stderr, "malloc(%uz) failed\n", size);
    }
    printf("malloc: %p:%uz\n", p, size);
    
    return p;
}

//申请新的数据块
static void * mem_palloc_block(mem_pool_t *pool, size_t size)
{
    u_char *m;
    size_t psize;
    mem_pool_t *p, *new, *current;

    psize = (size_t)(pool->d.end - (u_char *)pool);

    m = mem_memalign(MEM_POOL_ALIGNMENT, psize);
    if (m == NULL) {
      return NULL;
    }
    
    new = (mem_pool_t *)m;
    
    new->d.end = m + psize;
    new->d.next = NULL;
    new->d.failed = 0;

    m += sizeof(mem_pool_data_t);
    m = mem_align_ptr(m, MEM_ALIGNMENT);
    new->d.last = m + size;
    
    current = pool->current;

    for (p = current; p->d.next; p = p->d.next) {
        if (p->d.failed++ > 4) {
            current = p->d.next;
        }
    }

    p->d.next = new;
    
    pool->current = current ? current : new;

    return m;
}

//申请大块内存
static void *mem_palloc_large(mem_pool_t *pool, size_t size)
{
    void             *p;
    mem_uint_t        n;
    mem_pool_large_t *large;

    p = mem_alloc(size);
    if (p == NULL) {
        return NULL;
    }

    n = 0;

    for (large = pool->large; large; large = large->next) {
        if (large->alloc == NULL) {
            large->alloc = p;
            return p;
        }
        
        if (n++ > 3) {
            break;
        }
    }

    large = mem_palloc(pool, sizeof(mem_pool_large_t));
    if (large == NULL) {
        mem_free(p);
        return NULL;
    }

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

    return p;
}

//从内存池申请size大小的内存
void *mem_palloc(mem_pool_t *pool, size_t size)
{
    u_char *m;
    mem_pool_t *p;

    if (size <= pool->max) {
        p = pool->current;
        do {
            m = mem_align_ptr(p->d.last, MEM_ALIGNMENT);
            
            if ((size_t)(p->d.end - m) >= size) {
                p->d.last = m + size;
                return m;
            }
            p = p->d.next;
        } while (p);
        
        return mem_palloc_block(pool, size);
    }
    return mem_palloc_large(pool, size);
}

void *mem_memalign(size_t alignment, size_t size)
{
    void  *p;

    p = memalign(alignment, size);
    if (p == NULL) {
        fprintf(stderr, "memalign(%uz, %uz) failed\n", alignment, size);
    }

    printf("memalign: %p:%uz @%uz\n", p, size, alignment);

    return p;
}

mem_pool_t *mem_create_pool(size_t size)
{
    mem_pool_t *p;

    p = mem_memalign(MEM_POOL_ALIGNMENT, size); 
    if (p == NULL) {
        return NULL;
    }
    
    p->d.last = (u_char *)p + sizeof(mem_pool_t);
    p->d.end = (u_char *)p + size;
    p->d.next = NULL;
    p->d.failed = 0;

    size = size - sizeof(mem_pool_t);
    p->max = (size < MEM_MAX_ALLOC_FROM_POOL) ? size : MEM_MAX_ALLOC_FROM_POOL;
    p->current = p;
    p->large = NULL;
    p->cleanup = NULL;

    return p;
}


void mem_destroy_pool(mem_pool_t *pool)
{
    mem_pool_t *p, *n;
    mem_pool_large_t *l;
    mem_pool_cleanup_t *c;

    for (c = pool->cleanup; c; c = c->next) {
        if (c->handler) {
            c->handler(c->data);
        }
    }

    for (l = pool->large; l; l = l->next) {
        if (l->alloc) {
            mem_free(l->alloc);
        }
    }

    for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) {
        mem_free(p);
        if (n == NULL) {
            break;
        }
    }
}

测试c文件:main.c

#include "mem_palloc.h"

void dump_pool(mem_pool_t* pool)
{
    while (pool)
    {
        printf("pool = 0x%x\n", pool);
        printf("  .d\n");
        printf("    .last = 0x%x\n", pool->d.last);
        printf("    .end = 0x%x\n", pool->d.end);
        printf("    .next = 0x%x\n", pool->d.next);
        printf("    .failed = %d\n", pool->d.failed);
        printf("  .max = %d\n", pool->max);
        printf("  .current = 0x%x\n", pool->current);
        printf("  .large = 0x%x\n", pool->large);
        printf("  .cleanup = 0x%x\n", pool->cleanup);
        printf("available pool memory = %d\n\n", pool->d.end - pool->d.last);
        pool = pool->d.next;
    }
}

int main(int argc, char *argv[])
{
    mem_pool_t *pool;

    printf("--------------------------------\n");
    printf("create a new pool:\n");
    printf("--------------------------------\n");
    pool = mem_create_pool(1024);
    dump_pool(pool);

    printf("--------------------------------\n");
    printf("alloc block 1 from the pool:\n");
    printf("--------------------------------\n");
    mem_palloc(pool, 512);
    dump_pool(pool);

    printf("--------------------------------\n");
    printf("alloc block 2 from the pool:\n");
    printf("--------------------------------\n");
    mem_palloc(pool, 512);
    dump_pool(pool);

    printf("--------------------------------\n");
    printf("alloc block 3 from the pool :\n");
    printf("--------------------------------\n");
    mem_palloc(pool, 512);
    dump_pool(pool);

    mem_destroy_pool(pool);
    return 0;
}

Makefile文件:

CC=gcc
CFLAGS=-Wall -std=c99 -pedantic
EXEC=mem_pool_test
OBJETCS= main.o mem_palloc.o

all: mem_pool_test

mem_pool_test: $(OBJETCS)
	$(CC) $(CFLAGS) $(OBJETCS) -o mem_pool_test

main.o: main.c mem_palloc.h
	$(CC) $(CFLAGS) -c main.c -o main.o

mem_palloc.o: mem_palloc.c mem_palloc.h
	$(CC) $(CFLAGS) -c mem_palloc.c -o mem_palloc.o 

clean:
	rm -f $(EXEC) *.o *~

运行结果:

[nginx@localhost mempool]$ ./mem_pool_test 
--------------------------------
create a new pool:
--------------------------------
memalign: 0x143f010:1024 @16
pool = 0x143f010
  .d
    .last = 0x143f050
    .end = 0x143f410
    .next = 0x0
    .failed = 0
  .max = 960
  .current = 0x143f010
  .large = 0x0
  .cleanup = 0x0
available pool memory = 960

--------------------------------
alloc block 1 from the pool:
--------------------------------
pool = 0x143f010
  .d
    .last = 0x143f250
    .end = 0x143f410
    .next = 0x0
    .failed = 0
  .max = 960
  .current = 0x143f010
  .large = 0x0
  .cleanup = 0x0
available pool memory = 448

--------------------------------
alloc block 2 from the pool:
--------------------------------
memalign: 0x143f420:1024 @16
pool = 0x143f010
  .d
    .last = 0x143f250
    .end = 0x143f410
    .next = 0x143f420
    .failed = 0
  .max = 960
  .current = 0x143f010
  .large = 0x0
  .cleanup = 0x0
available pool memory = 448

pool = 0x143f420
  .d
    .last = 0x143f640
    .end = 0x143f820
    .next = 0x0
    .failed = 0
  .max = 0
  .current = 0x0
  .large = 0x0
  .cleanup = 0x0
available pool memory = 480

--------------------------------
alloc block 3 from the pool :
--------------------------------
memalign: 0x143f830:1024 @16
pool = 0x143f010
  .d
    .last = 0x143f250
    .end = 0x143f410
    .next = 0x143f420
    .failed = 1
  .max = 960
  .current = 0x143f010
  .large = 0x0
  .cleanup = 0x0
available pool memory = 448

pool = 0x143f420
  .d
    .last = 0x143f640
    .end = 0x143f820
    .next = 0x143f830
    .failed = 0
  .max = 0
  .current = 0x0
  .large = 0x0
  .cleanup = 0x0
available pool memory = 480

pool = 0x143f830
  .d
    .last = 0x143fa50
    .end = 0x143fc30
    .next = 0x0
    .failed = 0
  .max = 0
  .current = 0x0
  .large = 0x0
  .cleanup = 0x0
available pool memory = 480

致谢:

参考了博主阿波321的博客https://blog.csdn.net/livelylittlefish/article/details/6586946

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值