简易内存池

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
 
 
#define MP_ALIGNMENT               32
#define MP_PAGE_SIZE            4096
#define MP_MAX_ALLOC_FROM_POOL    (MP_PAGE_SIZE-1)
 
#define mp_align(n, alignment) (((n)+(alignment-1)) & ~(alignment-1))
#define mp_align_ptr(p, alignment) (void *)((((size_t)p)+(alignment-1)) & ~(alignment-1))
 
 
 
 
// 大块内存 大小>4k
struct mp_large_s {
    struct mp_large_s *next;     // 指向下一个大块内存
    void *alloc;                // 分配内存的指针
};
 
// 小块内存 大小=4k
struct mp_node_s {
    unsigned char *last;        // 指向当前可用内存的位置
    unsigned char *end;            // 小块内存的结束位置
    
    struct mp_node_s *next;        // 指向下一个小块内存
    size_t failed;                // 
};
 
// 内存池管理器
struct mp_pool_s {
    size_t max;                    // 大小块区分阈值,这里是4k大小
 
    struct mp_node_s *current;    // 当前可用小块内存
    struct mp_large_s *large;    // 大块内存链表头
 
    struct mp_node_s head[0];    // 柔性数组,在这里相当于是当前小块内存的标签
};
/**
 * The atomic counter structure.
 */
typedef struct {
    volatile int32_t cnt; /**< An internal counter value. */
}mp_atomic32_t;

/**
 * Atomically set a counter to a 32-bit value.
 *
 * @param v
 *   A pointer to the atomic counter.
 * @param new_value
 *   The new value for the counter.
 */
static inline void
mp_atomic32_set(mp_atomic32_t *v, int32_t new_value)
{
    v->cnt = new_value;
}

/**
 * Atomically add a 32-bit value to a counter and return the result.
 *
 * Atomically adds the 32-bits value (inc) to the atomic counter (v) and
 * returns the value of v after addition.
 *
 * @param v
 *   A pointer to the atomic counter.
 * @param inc
 *   The value to be added to the counter.
 * @return
 *   The value of v after the addition.
 */
static inline int32_t
mp_atomic32_add_return(mp_atomic32_t *v, int32_t inc)
{
    return __sync_add_and_fetch(&v->cnt, inc);
}

/**
 * Atomically add a 32-bit value to an atomic counter.
 *
 * @param v
 *   A pointer to the atomic counter.
 * @param inc
 *   The value to be added to the counter.
 */
static inline void
mp_atomic32_add(mp_atomic32_t *v, int32_t inc)
{
    __sync_fetch_and_add(&v->cnt, inc);
}

/**
 * Atomically subtract a 32-bit value from an atomic counter.
 *
 * @param v
 *   A pointer to the atomic counter.
 * @param dec
 *   The value to be subtracted from the counter.
 */
static inline void
mp_atomic32_sub(mp_atomic32_t *v, int32_t dec)
{
    __sync_fetch_and_sub(&v->cnt, dec);
}
/**
 * Atomically subtract a 32-bit value from a counter and return
 * the result.
 *
 * Atomically subtracts the 32-bit value (inc) from the atomic counter
 * (v) and returns the value of v after the subtraction.
 *
 * @param v
 *   A pointer to the atomic counter.
 * @param dec
 *   The value to be subtracted from the counter.
 * @return
 *   The value of v after the subtraction.
 */
static inline int32_t
mp_atomic32_sub_return(mp_atomic32_t *v, int32_t dec)
{
    return __sync_sub_and_fetch(&v->cnt, dec);
}

typedef struct mp_buf_s {
    struct mp_pool_s * pool;    
    mp_atomic32_t  a;
    char ptr[0];
}mp_buf_t;

#define MP_ALIGN_SIZE sizeof(mp_buf_t)
// 创建内存池
struct mp_pool_s *mp_create_pool(size_t size);
 
// 销毁内存池
void mp_destory_pool(struct mp_pool_s *pool);
 
// 分配内存,内存对齐
void *mp_alloc(struct mp_pool_s *pool, size_t size);
 
// 分配内存,内存不对齐
void *mp_nalloc(struct mp_pool_s *pool, size_t size);
 
// 分配并初始化内存为0
void *mp_calloc(struct mp_pool_s *pool, size_t size);
 
// 释放内存
void mp_free(struct mp_pool_s *pool, void *p);
 
 
 
struct mp_pool_s *mp_create_pool(size_t size) {
    struct mp_pool_s *p;
 
    // 这里不使用malloc分配内存,是因为malloc适用于分配小内存,分配大内存容易出错
    // posix_memalign这个函数是linux系统提供,linux在内核对也有2种内存分配管理机制,对应着malloc和posix_memalign
    // 另外,管理器和第一个小内存块保存在一起,这么做是为了尽量保证不要出现内存碎片化的情况出现,因为内存池就是为了不要出现内存碎片
    int ret = posix_memalign((void **)&p, MP_ALIGNMENT, size + sizeof(struct mp_pool_s) + sizeof(struct mp_node_s));
    if (ret) {
        return NULL;
    }
    
    // 小块最大只能是4k大小(一页)
    p->max = (size < MP_MAX_ALLOC_FROM_POOL) ? size : MP_MAX_ALLOC_FROM_POOL;
    p->current = p->head;
    p->large = NULL;
 
    p->head->last = (unsigned char *)p + sizeof(struct mp_pool_s) + sizeof(struct mp_node_s);
    p->head->end = p->head->last + size;
 
    p->head->failed = 0;
 
    return p;
 
}
 
void mp_destory_pool(struct mp_pool_s *pool) {
    struct mp_node_s *h, *n;
    struct mp_large_s *l;
 
    // 先释放大块
    for (l = pool->large; l; l = l->next) {
        if (l->alloc) {
            free(l->alloc);
        }
    }
 
    // 释放小块
    h = pool->head->next;
    while (h) {
        n = h->next;
        free(h);
        h = n;
    }
 
    free(pool);
}
 
void mp_reset_pool(struct mp_pool_s *pool) {
 
    struct mp_node_s *h;
    struct mp_large_s *l;
 
    for (l = pool->large; l; l = l->next) {
        if (l->alloc) {
            free(l->alloc);
        }
    }
 
    pool->large = NULL;
 
    for (h = pool->head; h; h = h->next) {
        h->last = (unsigned char *)h + sizeof(struct mp_node_s);
    }
 
}
 
static void *mp_alloc_block(struct mp_pool_s *pool, size_t size) {
    unsigned char *m;
 
    struct mp_node_s *h = pool->head;                            // 获取小块内存头节点
    size_t psize = (size_t)(h->end - (unsigned char *)h);        // 获取小块内存的大小
    
    int ret = posix_memalign((void **)&m, MP_ALIGNMENT, psize);    // 分配内存
    if (ret) return NULL;
 
    struct mp_node_s *p, *new_node, *current;
    new_node = (struct mp_node_s*)m;                            // 新分配的小块内存指针
 
    new_node->end = m + psize;                                    // 设置小块内存的结束地址
    new_node->next = NULL;
    new_node->failed = 0;
 
    m += sizeof(struct mp_node_s);                                // 小块内存start指针
    m = mp_align_ptr(m, MP_ALIGNMENT);                            // 分配内存,内存对齐
    new_node->last = m + size;                                    // 设置结尾位置,这里设置的结尾表达的的意思是,从新的小块内存中分配了内存
 
    current = pool->current;                                    // 获取当前小块内存
 
    for (p = current; p->next; p = p->next) {                    // 寻找小块内存最后一个节点
        if (p->failed++ > 4) {                                    // 优化搜寻小块内存的速度,如果一个节点被4次跳过,说明这个节点可用内存很小了,通过设置新的current节点,优化搜索可用小块内存的时间
            current = p->next;
        }
    }
 
    p->next = new_node;                                            // 将新的小块内存加入到链表结尾
    pool->current = current ? current : new_node;                
 
    return m;
 
}
 
static void *mp_alloc_large(struct mp_pool_s *pool, size_t size) {
    void *p;
    int ret = posix_memalign(&p, MP_ALIGNMENT, size);                // 生成大块内存
    if (p == NULL) return NULL;
 
    size_t n = 0;    
    struct mp_large_s *large;
    for (large = pool->large; large; large = large->next) {        
        if (large->alloc == NULL) {
            large->alloc = p;
            return p;
        }
        if (n ++ > 3) break;
    }
 
    large = mp_alloc(pool, sizeof(struct mp_large_s));
    if (large == NULL) {
        free(p);
        return NULL;
    }
 
    large->alloc = p;                    // 头插法
    large->next = pool->large;
    pool->large = large;
 
    return p;
}
 
void *mp_memalign(struct mp_pool_s *pool, size_t size, size_t alignment) {
    void *p;
    
    int ret = posix_memalign(&p, MP_ALIGNMENT, size);
    if (ret) {
        return NULL;
    }
 
    struct mp_large_s *large = mp_alloc(pool, sizeof(struct mp_large_s));
    if (large == NULL) {
        free(p);
        return NULL;
    }
 
    large->alloc = p;
    large->next = pool->large;
    pool->large = large;
 
    return p;
}
 
 
 
 
void *mp_alloc(struct mp_pool_s *pool, size_t size) {
    unsigned char *m;
    struct mp_node_s *p;
 
    // 判断大小块
    if (size <= pool->max) {
        // p = 当前小块
        p = pool->current;
        
        // 遍历小块内存链表
        do {
            // 内存对齐
            m = mp_align_ptr(p->last, MP_ALIGNMENT);
            if ((size_t)(p->end - m) >= size) {
                p->last = m + size;
                return m;
            }
            p = p->next;
        } while (p);
 
        // 如果没有小块内存可分配,就再生成一个小块内存,从其中分配内存
        return mp_alloc_block(pool, size);
    }
 
    // 如果属于大块内存,则分配大块内存
    return mp_alloc_large(pool, size);
}
 
 
void *mp_nalloc(struct mp_pool_s *pool, size_t size) {
    unsigned char *m;
    struct mp_node_s *p;
 
    if (size <= pool->max) {
        p = pool->current;
 
        do {
            m = p->last;
            if ((size_t)(p->end - m) >= size) {
                p->last = m+size;
                return m;
            }
            p = p->next;
        } while (p);
 
        return mp_alloc_block(pool, size);
    }
 
    return mp_alloc_large(pool, size);
    
}
 
void *mp_calloc(struct mp_pool_s *pool, size_t size) {
 
    void *p = mp_alloc(pool, size);
    if (p) {
        memset(p, 0, size);
    }
 
    return p;
    
}
 
void mp_free(struct mp_pool_s *pool, void *p) {
 
    struct mp_large_s *l;
    for (l = pool->large; l; l = l->next) {
        if (p == l->alloc) {
            free(l->alloc);
            l->alloc = NULL;
 
            return ;
        }
    }
    
}

typedef struct {
    struct mp_pool_s * pool;
}session_t;

void mp_buf_atomic_inc(void * buf)
{
    mp_buf_t * mp_buf = (mp_buf_t*)((char*)buf - MP_ALIGN_SIZE);
    mp_atomic32_add(&mp_buf->a, 1);
}

void mp_buf_atomic_dec(void * buf)
{
    mp_buf_t * mp_buf = (mp_buf_t*)((char*)buf - MP_ALIGN_SIZE);
    mp_atomic32_sub(&mp_buf->a, 1);
}

enum {
    MEM_IS_NORMAL,
    MEM_IS_MEMPOOL,
}
//该接口调用后可以正常释放
//MEM_IS_MEMPOOL类型的 调用mp_buf_free(buf)
//MEM_IS_NORMAL类型的调用 free()
int io_send_buf(void * buf, int type)
{
    if (type == MEM_IS_NORMAL) {
        //尽量发送,直到发送成功,或者失败
    }else {
        //可以放到c->io_pool上延迟发送
        //如果挂载到c->io_pool上,则调用mp_buf_atomic_inc增加引用计数
        //在io模块调用mp_buf_free进行释放,要保证buf->pool不会先于buf释放
    }

}

void * mp_buf_alloc(session_t * session, size_t size) {
    size_t total_size = size + MP_ALIGN_SIZE;
    struct mp_pool_s * pool = session->pool;
    void * p = mp_alloc(pool, total_size);
    if (p == NULL)
        return NULL;

    mp_buf_t * buf = (mp_buf_t *)p;
    buf->pool = pool;
    mp_atomic32_set(&buf->a, 1);
    return  (void*)(buf + 1);
}

void mp_buf_free(void * buf)
{
    mp_buf_t * mp_buf = (mp_buf_t*)((char*)buf - MP_ALIGN_SIZE);
    if (mp_atomic32_sub_return(&mp_buf->a, 1) == 0) {
        mp_free(mp_buf->pool, buf);
    }
}


int main(int argc, char *argv[]) {
 
    int size = 1 << 12;
    session_t sess = {NULL};
    sess.pool = mp_create_pool(size);
 
    int i = 0;
    for (i = 0;i < 10;i ++) {
        void *mp = mp_buf_alloc(&sess, 512);
        mp_buf_free(mp);
    }
 
    //printf("mp_create_pool: %ld\n", p->max);
    printf("mp_align(123, 32): %d, mp_align(17, 32): %d\n", mp_align(24, 32), mp_align(17, 32));
    //printf("mp_align_ptr(p->current, 32): %lx, p->current: %lx, mp_align(p->large, 32): %lx, p->large: %lx\n", mp_align_ptr(p->current, 32), p->current, mp_align_ptr(p->large, 32), p->large);
 
    int j = 0;
    for (i = 0;i < 5;i ++) {
        char *pp = mp_buf_alloc(&sess, 32);
        for (j = 0;j < 32;j ++) {
            if (pp[j]) {
                printf("calloc wrong\n");
            }
            printf("calloc success\n");
        }
    }
 
    //printf("mp_reset_pool\n");
 
    for (i = 0;i < 5;i ++) {
        void *l = mp_buf_alloc(&sess, 8192);
        mp_buf_free(sess.pool);
    }
 
    mp_reset_pool(sess.pool);
 
    //printf("mp_destory_pool\n");
    for (i = 0;i < 58;i ++) {
        mp_buf_alloc(&sess, 256);
    }
 
    mp_destory_pool(sess.pool);
 
    return 0;
 
}
 
 
 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值