Nginx内存池__2018.06.14

Nginx内存池各部分数据结构示意图:

Ngx_pool.h

#ifndef NGX_POOL_H
#define NGX_POOL_H
typedef unsigned char u_char;
typedef unsigned int u_int;
typedef struct ngx_pool_s ngx_pool_t;
typedef struct ngx_pool_large_s ngx_pool_large_t;
const int MAX = 4096;

const int NGX_ALIGNMENT = sizeof(unsigned long);
#define ngx_align_ptr(p, a)\
	(u_char *) (((unsigned int) (p) + ((unsigned int) a - 1)) & ~((unsigned int) a - 1))


typedef struct
{
	u_char		*last;
	u_char		*end;
	ngx_pool_t	*next;
	u_int		failed;
}ngx_pool_data_t;

struct ngx_pool_s
{
	ngx_pool_data_t		d;
	ngx_pool_t			*current;//指向当前内存的指针。
	ngx_pool_large_t	*large;
};
struct ngx_pool_large_s
{
	ngx_pool_large_t	*next;
	void				*alloc;
};
class NgxMemPool
{
public:
	//创建ngx内存池
	void ngx_create_pool(u_int size);
	//销毁ngx内存池
	void ngx_destroy_pool();
	//重置内存池
	void ngx_reset_pool();
	//开辟内存,对齐
	void* ngx_palloc(u_int size);
	//开辟内存,不对齐
	void* ngx_pnalloc(u_int size);
	//把内存归还给内存池
	bool ngx_pfree(void *p);

	//开辟小块内存
	void *ngx_palloc_small(u_int size, int align);
	//开辟新的小块
	void *ngx_palloc_block(u_int size);
	//开辟大块内存
	void *ngx_palloc_large(u_int size);
private:
	ngx_pool_t *_pool;
};
#endif

Ngx_pool.cpp

#include "Ngx_pool.h"
#include <iostream>
#include <vld.h>

using namespace std;
//创建ngx内存池
void NgxMemPool::ngx_create_pool(u_int size)
{
	_pool = (ngx_pool_t*)malloc(size);
	if (NULL == _pool)
	{
		return;
	}
	_pool->d.last = (u_char*)_pool + sizeof(ngx_pool_t);
	_pool->d.end = (u_char*)_pool + size;
	_pool->d.next = NULL;
	_pool->d.failed = 0;
	_pool->current = _pool;//当前指针位置
	_pool->large = NULL;
}
//销毁ngx内存池
void NgxMemPool::ngx_destroy_pool()
{
	//先释放large指向外部开辟的大内存
	ngx_pool_large_t	*pLarge;
	for (pLarge = _pool->large; pLarge != NULL; pLarge = pLarge->next)
	{
		if (pLarge->alloc)
		{
			free(pLarge->alloc);
			pLarge->next = NULL;
		}
	}
	ngx_pool_t			*p;
	ngx_pool_t			*n;

	for (p = _pool, n = _pool->d.next;; p = n)
	{
		free(p);
		p = NULL;
		if (NULL == n)
		{
			break;
		}
	}

}
//重置内存池
void NgxMemPool::ngx_reset_pool()
{
	ngx_pool_large_t	*pLarge;//指向内存池外开辟的大块内存
	ngx_pool_t			*p;//指向内存池的指针
	//先释放内存池外开辟的大块内存
	for (pLarge = _pool->large; pLarge != NULL; pLarge = pLarge->next)
	{
		if (pLarge->alloc)
		{
			free(pLarge->next);
			pLarge->alloc = NULL;
		}
	}
	//再重置内存池中的内存
	for (p = _pool; p; p = p->d.next)
	{
		p->d.last = (u_char*)p + sizeof(ngx_pool_t);
	}
	_pool->current = _pool;
}
//开辟内存,对齐
void* NgxMemPool::ngx_palloc(u_int size)
{
	if (size <= MAX)
	{
		return ngx_palloc_small(size,0);
	}
	return ngx_palloc_large(size);
}
//把内存归还给内存池
bool NgxMemPool::ngx_pfree(void *p)
{
	ngx_pool_large_t *pLarge;
	//只检查是否是大内存块,如果是大内存块则释放
	for (pLarge = _pool->large; pLarge; pLarge->next)
	{
		if (p == pLarge->alloc)
		{
			free(pLarge->alloc);
			pLarge->alloc = NULL;
			return true;
		}
	}
	return false;
}
//开辟小块内存
void*NgxMemPool::ngx_palloc_small(u_int size,int align)
{
	u_char		*m;
	ngx_pool_t	*p;
	p = _pool->current;
	do {
		m = p->d.last;
		if (align)
		{
			m = ngx_align_ptr(m,NGX_ALIGNMENT);
		}
		if ((u_int)(p->d.end - m) >= size)
		{
			p->d.last = m + size;
			return m;
		}
	} while (p);
	//开辟内存过大,内存池中没有合适的内存,则重新开辟指定大小的内存块
	return ngx_palloc_block(size);
}
//开辟新的小内存块
void *NgxMemPool::ngx_palloc_block(u_int size)
{
	u_int	psize;
	u_char	*m;
	ngx_pool_t	*pnew, *t;

	psize = (u_int)(_pool->d.end-(u_char*)_pool);
	m = (u_char*)malloc(psize);
	if (NULL == m)
		return NULL;

	pnew = (ngx_pool_t*)m;
	pnew->d.end = m + psize;
	pnew->d.next = NULL;
	pnew->d.failed = 0;

	/*将m指针移动数据头的大小位置*/
	m += sizeof(ngx_pool_data_t);
	/*进行内存对齐计算*/
	m = ngx_align_ptr(m, NGX_ALIGNMENT);
	/*设置新内存块的last,即申请使用size大小的内存*/
	pnew->d.last = m + size;

	/*对链表进行整理current指针要重新确认*/

	/*这里循环用来寻找最后一个节点 */
	for (t = _pool->current; t->d.next != NULL; t = t->d.next)
	{
		if (t->d.failed++ > 4)	//failed的值只在此处被修改
		{
			t->current = t->d.next;	//失败4次以上移动current指针  
		}
	}
	/*在循环中next可能会指向NULL 所以current也可能会被置NULL*/
	t->d.next = pnew;  //将这次分配的内存块pnew加入该内存池链表中

					   /*对current确认为NULL时则重新确认位置*/
	_pool->current = t->current ? t->current : pnew;

	return m;
}
//开辟大块内存
void *NgxMemPool::ngx_palloc_large(u_int size)
{
	void              *p;
	u_int         n = 0;
	ngx_pool_large_t  *large;

	// 直接在系统堆中分配一块空间  
	p = (void *)malloc(size);
	if (p == NULL)
	{
		return NULL;
	}

	// 查找到一个空的large区,如果有,则将刚才分配的空间交由它管理  
	for (large = _pool->large; large; large = large->next)
	{
		if (NULL == large->alloc)
		{
			large->alloc = p;
			return p;
		}
		if (n++ > 3)
		{
			break;
		}
	}
	//为了提高效率, 如果在三次内没有找到空的large结构体,则创建一个
	large = (ngx_pool_large_t*)ngx_palloc_small(size, 1);
	if (NULL == large)
	{
		free(p);
		return NULL;
	}
	large->alloc = p;
	large->next = _pool->large;
	_pool->large = large;
	return p;
}
int main()
{
	NgxMemPool p;
	p.ngx_create_pool(4096);
	int *a = (int*)p.ngx_palloc(sizeof(int));
	*a = 10;
	cout << "a=" << *a << endl;
	p.ngx_pfree(a);
	p.ngx_destroy_pool();
}


阅读更多

关于 nginx 内存池的疑问

06-26

[code=c] 1: static void *rn 2: ngx_palloc_block(ngx_pool_t *pool, size_t size)rn 3: rn 4: u_char *m;rn 5: size_t psize;rn 6: ngx_pool_t *p, *new, *current;rn 7: rn 8: psize = (size_t) (pool->d.end - (u_char *) pool);//计算内存池第一个内存块的大小rn 9: rn 10: m = ngx_memalign(NGX_POOL_ALIGNMENT, psize, pool->log);//分配和第一个内存块同样大小的内存块rn 11: if (m == NULL) rn 12: return NULL;rn 13: rn 14: rn 15: new = (ngx_pool_t *) m;rn 16: rn 17: new->d.end = m + psize;//设置新内存块的endrn 18: new->d.next = NULL;rn 19: new->d.failed = 0;rn 20: rn 21: m += sizeof(ngx_pool_data_t);//将指针m移动到d后面的一个位置,作为起始位置rn 22: m = ngx_align_ptr(m, NGX_ALIGNMENT);//对m指针按4字节对齐处理rn 23: new->d.last = m + size;//设置新内存块的last,即申请使用size大小的内存rn 24: rn 25: current = pool->current;rn 26: //这里的循环用来找最后一个链表节点,这里failed用来控制循环的长度,如果分配失败次数达到5次,rn 27: //就忽略,不需要每次都从头找起rn 28: for (p = current; p->d.next; p = p->d.next) rn 29: if (p->d.failed++ > 4) rn 30: current = p->d.next;rn 31: rn 32: rn 33: rn 34: p->d.next = new;rn 35: rn 36: pool->current = current ? current : new;rn 37: rn 38: return m;rn 39: [/code]rnrn以上这个函数是在遍历内存池没有找到可用大小的内存块的时候重新分配一块内存的函数.假设一个内存块大小是1024B前面占用40字节,然后后面实际可用的内存区是984B,正好我们需要申请的内存也是984B,但是现在有两种情况,如果ngx_memalign对齐指针之后指针正好指在984B内存区的起始位置,那申请应该能够给成功,如果ngx_memalign对齐指针之后指针向后偏移了几个字节,那么实际可用的内存区就不够984B了?这个函数难道没有什么问题吗?rnrn求解释?为什么ngx_memalign指针对齐之后还能确保后面的分配能够正常分配?

没有更多推荐了,返回首页