学习笔记:内存池

内存池是一种优化内存分配的技术,通过预先分配一大块内存并进行管理,减少了内存碎片和分配效率问题。本文详细介绍了内存池的原理,包括小块和大块内存管理,并以nginx的内存池实现为例进行说明,同时讲解了内存对齐和内存泄漏检测。此外,还提供了一个类似nginx内存池的简单实现示例。
摘要由CSDN通过智能技术生成

内存池解决了什么?

  1. 减少内存碎片,提高分配效率
  2. 内存泄漏也可采用内存池;用内存池替换之后,判断泄露是否是在内存池之外。

几个概念

内存页

getconf PAGE_SIZE #4096, 4k

虚拟内存和物理内存的映射,采用内存页的方式。既不同进程,虚拟内存地址相同,但是对应的物理内存地址不一样。
4G内存,为每一个内存分配独一无二的编号,那么就需要2^32个数字,既是用32位长的二进制数表示,或者8位长的十六进制数表示。
如果虚拟内存和物理内存的映射采用一一对应的映射关系,既是物理地址id = table[虚拟内存地址id],那么这个table也得2^32 * 地址id长。
Linux采用两级页表的方式实现了对内存的映射。
https://blog.csdn.net/wangaifei1/article/details/109052535
https://blog.csdn.net/qq_37653144/article/details/82850368
https://www.cnblogs.com/vamei/p/9329278.html
逻辑地址,线性地址,物理地址概念
https://www.cnblogs.com/kukudi/p/11416993.html

碎片

https://www.zhihu.com/question/51836333

内存对齐

https://blog.csdn.net/qq_31821675/article/details/72853551


以nginx的内存池举例

src/core/ngx_palloc.h,注释我自己加的

/*
 * NGX_MAX_ALLOC_FROM_POOL should be (ngx_pagesize - 1), i.e. 4095 on x86.
 * On Windows NT it decreases a number of locked pages in a kernel.
 */
#define NGX_MAX_ALLOC_FROM_POOL  (ngx_pagesize - 1)

struct ngx_pool_large_s {//大块
    ngx_pool_large_t     *next; //以链表的形式串起来
    void                 *alloc;//对应的指针
};


typedef struct {//小块
    u_char               *last;//小块的未使用位置的起始地址
    u_char               *end; //小块的未使用位置的尾地址
    ngx_pool_t           *next;//以链表的形式串起来
    ngx_uint_t            failed;//查询空闲位置失败次数
} ngx_pool_data_t;


struct ngx_pool_s {
    ngx_pool_data_t       d;      //小块
    size_t                max;    //区分小块与大块的分界线
    ngx_pool_t           *current;//小块的链表
    ngx_chain_t          *chain;  //??
    ngx_pool_large_t     *large;  //大块的链表
    ngx_pool_cleanup_t   *cleanup;//??
    ngx_log_t            *log;    //??
};

src/core/ngx_palloc.c,注释我自己加的

ngx_pool_t *
ngx_create_pool(size_t size, ngx_log_t *log)//创建内存池
{
    ngx_pool_t  *p;

    p = ngx_memalign(NGX_POOL_ALIGNMENT, size, log);//malloc
    if (p == NULL) {
        return NULL;
    }

    p->d.last = (u_char *) p + sizeof(ngx_pool_t);//小块的起始地址
    p->d.end = (u_char *) p + size;               //小块的尾地址
    p->d.next = NULL;                             //链表
    p->d.failed = 0;                              //

    size = size - sizeof(ngx_pool_t);
    p->max = (size < NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL;

    p->current = p;                               //小块链表
    p->chain = NULL;
    p->large = NULL;                              //大块链表
    p->cleanup = NULL;
    p->log = log;

    return p;
}

void
ngx_destroy_pool(ngx_pool_t *pool)
{
    //...
	
    for (l = pool->large; l; l = l->next) {	//释放链表
        if (l->alloc) {
            ngx_free(l->alloc);
        }
    }

    for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) {	//释放链表!!注意这里是pool->d, 而不是pool->current
        ngx_free(p);

        if (n == NULL) {
            break;
        }
    }
}

void *
ngx_pnalloc(ngx_pool_t *pool, size_t size)
{
#if !(NGX_DEBUG_PALLOC)
    if (size <= pool->max) {
        return ngx_palloc_small(pool, size, 0);
    }
#endif

    return ngx_palloc_large(pool, size);
}


static ngx_inline void *
ngx_palloc_small(ngx_pool_t *pool, size_t size, ngx_uint_t align)
{
    u_char      *m;
    ngx_pool_t  *p;

    p = pool->current;

    do {
        m = p->d.last;

        if (align) {
        	//定义在src/core/ngx_config.h,内存对齐
        	//#define ngx_align_ptr(p, a)                                                   \
			//    (u_char *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1))
            m = ngx_align_ptr(m, NGX_ALIGNMENT);
        }

        if ((size_t) (p->d.end - m) >= size) {//判断是否有空位
            p->d.last = m + size;

            return m;
        }

        p = p->d.next;

    } while (p);

    return ngx_palloc_block(pool, size);//在链表尾追加,并返回对应内存地址
}


static void *
ngx_palloc_block(ngx_pool_t *pool, size_t size)
{
    u_char      *m;
    size_t       psize;
    ngx_pool_t  *p, *new;

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

    m = ngx_memalign(NGX_POOL_ALIGNMENT, psize, pool->log);
    if (m == NULL) {
        return NULL;
    }

    new = (ngx_pool_t *) m;

    new->d.end = m + psize;
    new->d.next = NULL;
    new->d.failed = 0;

    m += sizeof(ngx_pool_data_t);
    m = ngx_align_ptr(m, NGX_ALIGNMENT);
    new->d.last = m + size;

    for (p = pool->current; p->d.next; p = p->d.next) {
        if (p->d.failed++ > 4) {
            pool->current = p->d.next;//小块用完了的, current指向下一个小块
        }
    }

    p->d.next = new;

    return m;
}


static void *
ngx_palloc_large(ngx_pool_t *pool, size_t size)
{
    void              *p;
    ngx_uint_t         n;
    ngx_pool_large_t  *large;

    p = ngx_alloc(size, pool->log);
    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 = ngx_palloc_small(pool, sizeof(ngx_pool_large_t), 1);//在小块中申请大块的头
    if (large == NULL) {
        ngx_free(p);
        return NULL;
    }

    large->alloc = p;
    large->next = pool->large;
    pool->large = large;//直接在链表头添加

    return p;
}

ngx_int_t
ngx_pfree(ngx_pool_t *pool, void *p)
{
    ngx_pool_large_t  *l;

    for (l = pool->large; l; l = l->next) {//只是释放大块
        if (p == l->alloc) {
            ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0,
                           "free: %p", l->alloc);
            ngx_free(l->alloc);
            l->alloc = NULL;

            return NGX_OK;
        }
    }

    return NGX_DECLINED;
}

#include <stdio.h>
#include <stdlib.h>

#include <pthread.h>

#define MP_PAGE_SIZE             4096
#define MP_MAX_ALLOC_FROM_POOL   (MP_PAGE_SIZE-1)

struct mp_large_s{
	struct mp_large_s *next;
	void * alloc;
};

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;
	struct mp_node_s *current;
	struct mp_large_s *large;

	struct mp_node_s head[0];
};

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);
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 *pool = malloc(sizeof(struct mp_pool_s) + sizeof(struct mp_node_s) + size);
	//posix_memalign 分配超大块

	pool->max = (size < MP_MAX_ALLOC_FROM_POOL)?size:MP_MAX_ALLOC_FROM_POOL;
	pool->current = pool->head;
	pool->large = NULL;

	pool->head->last = (unsigned char *)pool + sizeof(struct mp_pool_s) + sizeof(struct mp_node_s);
	pool->head->end = pool->head->last + size;
	pool->head->failed = 0;

	return pool;
}

void mp_destory_pool(struct mp_pool_s *pool){
	struct mp_large_s *l;
	for(l=pool->large;l!=NULL;l=l->next){
		if(l->alloc != NULL){
			free(l->alloc);
		}
	}

	struct mp_node_s *h,*n;
	h = pool->head->next;
	while(h!=NULL){
		n = h->next;
		free(h);
		h = n;
	}

	free(pool);
}


void * mp_alloc_block(struct mp_pool_s *pool,size_t size){
	size_t psize = pool->head->end - (unsigned char *)pool->head;

	unsigned char* m = malloc(psize);
	if(m == NULL){
		return NULL;
	}

	struct mp_node_s *new_node = (struct mp_node_s*)m;
	new_node->last = m + sizeof(struct mp_node_s);
	new_node->end = m + psize;
	new_node->next = NULL;
	new_node->failed = 0;

	m = new_node->last;
	new_node->last = m + size;

	struct mp_node_s *p;
	for(p=pool->current;p->next!=NULL;p=p->next){
		if((p->failed++)>4){
			pool->current = p->next;
		}
	}
	p->next = new_node;

	return m;
}

void* mp_alloc_large(struct mp_pool_s *pool,size_t size){
	void *p = malloc(size);
	if(p == NULL){
		return NULL;
	}


	int n=0;
	struct mp_large_s *large;
	for(large=pool->large;large!=NULL;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_alloc(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_reset_pool(struct mp_pool_s *pool){
	struct mp_large_s *l;
	for(l=pool->large;l!=NULL;l=l->next){
		if(l->alloc != NULL){
			free(l->alloc);
		}
	}

	pool->large = NULL;

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


void mp_free(struct mp_pool_s *pool,void *p){
	struct mp_large_s *l;
	for(l=pool->large;l!=NULL;l=l->next){
		if(p == l->alloc){
			free(l->alloc);
			l->alloc=NULL;
			
			return;
		}
	}
}


int main(int argc, char *argv[]) {
	int size = 1 << 12;

	struct mp_pool_s *p = mp_create_pool(size);

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

		void *mp = mp_alloc(p, 512);
		//mp_free(mp);
	}

	

	//printf("mp_reset_pool\n");

	for (i = 0;i < 5;i ++) {
		void *l = mp_alloc(p, 8192);
		mp_free(p, l);
	}

	mp_reset_pool(p);

	//printf("mp_destory_pool\n");
	for (i = 0;i < 58;i ++) {
		mp_alloc(p, 256);
	}

	mp_destory_pool(p);

	return 0;

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值