浅谈nginx内存池(二)
来源:互联网 发布:五线胆码的算法 编辑:程序博客网 时间:2024/06/05 00:14
首先是创建一个内存池----->ngx_create_pool:
///内存池的数据区的最大容量。
#define NGX_MAX_ALLOC_FROM_POOL (ngx_pagesize - 1) //此处的ngx_pagesize的大小在x86下通常是4k
ngx_pool_t * ngx_create_pool(size_t size, ngx_log_t *log)
{
ngx_pool_t *p;
///可以看到直接分配size大小,也就是说我们只能使用size-sizeof(ngx_pool_t)大小
p = ngx_alloc(size, log);
if (p == NULL) {
return NULL;
}
///开始初始化数据区。
///由于一开始数据区为空,因此last指向数据区的开始。
p->d.last = (u_char *) p + sizeof(ngx_pool_t);
///end也就是数据区的结束位置
p->d.end = (u_char *) p + size;
p->d.next = NULL;
p->d.failed = 0;
///这里才是我们真正能使用的大小。
size = size - sizeof(ngx_pool_t);
///然后设置max。内存池的最大值也就是size和最大容量之间的最小值。
p->max = (size < NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL;
///current表示当前的内存池。
p->current = p;
///其他的域置NULL。
p->chain = NULL;
p->large = NULL;
p->cleanup = NULL;
p->log = log;
return p;
}
2.接下来是如何从内存池中分配一块内存。
如图:
(1)分配一个较小的内存:图(a)或者图(b)
(a) (b)
(2)分配一个较大的内存:
有以下3个函数:
(1)ngx_palloc:这个函数分配的内存会对齐。
(2)ngx_calloc:这个函数用来分配一块清零的内存。
(3)ngx_pnalloc:这个函数分配的内存是不对齐的。
这三个函数差不多,就只需要分析一个就好。
void * ngx_palloc(ngx_pool_t *pool, size_t size)
{
u_char *m;
ngx_pool_t *p;
///首先判断当前申请的大小是否超过max,如果超过则说明是大块,此时进入large
if (size <= pool->max) {
///得到当前的内存池指针。
p = pool->current;
///开始遍历内存池,
do {
///首先对齐last指针。
m = ngx_align_ptr(p->d.last, NGX_ALIGNMENT);
/*
#define ngx_align_ptr(p, a) \
(u_char *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1))
这个宏使得到的内存地址为NGX_ALIGNMENT的倍数。数据对齐,可以避免cpu取值时,要进行两次IO。
*/
///然后得到当前内存池中的可用大小。如果大于请求大小,则直接返回当前的last,也就是数据的指针。
if ((size_t) (p->d.end - m) >= size) {
///更新last,然后返回前面保存的last。
p->d.last = m + size;
return m;
}
///否则继续遍历
p = p->d.next;
} while (p);
///到达这里说明内存池已经满掉,因此我们需要重新分配一个内存池然后链接到当前的data的next上。
return ngx_palloc_block(pool, size);
}
///申请大块。
return ngx_palloc_large(pool, size);
}
说明:这个函数的第一个参数是size,虽然我们传递进去的是size,但是我们真正可以使用的数据区大小是size-sizeof(ngx_pool_t)。
3.分配一块较大的内存,需要malloc一块ngx_pool_large_t,然后链接到内存池上。--->ngx_palloc_large
具体代码如下:
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;
///开始遍历large链表,如果有alloc(也就是内存区指针)为空,则直接指针赋值然后返回。一般第一次请求大块内存都会直接返回
for (large = pool->large; large; large = large->next) {
if (large->alloc == NULL) {
large->alloc = p;
return p;
}
if (n++ > 3) {
break;
}
}
///malloc一块ngx_pool_large_t。
large = ngx_palloc(pool, sizeof(ngx_pool_large_t));
if (large == NULL) {
ngx_free(p);
return NULL;
}
///然后链接数据区指针p到large。这里可以看到直接插入到large链表的头的。
large->alloc = p;
large->next = pool->large;
pool->large = large;
return p;
}
- 浅谈nginx内存池(二)
- 浅谈nginx内存池(一)
- 浅谈nginx内存池(三)
- 浅谈nginx内存池(四)
- 浅谈nginx内存池(五)
- nginx源码解析(二)-内存池与内存管理ngx_pool_t
- 浅谈内存泄漏(二)
- 浅谈内存泄漏(二)
- 浅谈内存泄漏(二)
- 浅谈内存泄漏(二)
- 浅谈内存的泄漏(二)
- nginx源码学习(二) 内存池结构 ngx_pool_t
- Nginx学习笔记(二十):内存池分析
- 浅谈C++中的内存管理(二)
- 浅谈Java内存管理(二)
- nginx内存池管理
- nginx中的内存池
- [zz] nginx 内存池
- Java:Collections框架
- XlistView
- [成长] 生病~
- LuoguP1720 月落乌啼算钱 解题报告【模拟+找规律/数学】
- 几种Java 枚举查找且不抛异常的实现及其优劣比较
- 浅谈nginx内存池(二)
- drawerlayout_demo
- map和foreach遍历的区别
- leetcode_218. The Skyline Problem ? 待解决
- ajax结合formdata实现往服务器上传文件
- 习题三(2)
- 使用OkHttp上传图片
- Spring Boot学习之旅:(七)logback配置日志
- require的基础使用(二)