内存分配相关
系统功能封装
内存相关的操作主要在 os/unix/ngx_alloc.{h,c} 和 core/ngx_palloc.{h,c} 下
其中 os/unix/ngx_alloc.{h,c} 封装了最基本的内存分配函数,是对c原有的malloc/free/memalign 等原有的函数的封装,对应的函数为:
- ngx_alloc 使用malloc分配内存空间
- ngx_calloc 使用malloc分配内存空间,并且将空间内容初始化为0
- ngx_memalign 返回基于一个指定的alignment大小的数值为对齐基数的空间
- ngx_free 对内存的释放操作
ngx的内存池
为了方便系统模块对内存的使用,方便内存的管理,nginx自己实现了进程池的机制来进行内存的分配和释放, 首先nginx会在特定的生命周期帮你统一建立内存池,当需要进行内存分配的时候统一通过内存池中的内存进行分配,最后nginx会在适当的时候释放内存池的资源,开发者只要在需要的时候对内存进行申请即可,不用过多考虑内存的释放等问题,大大提高了开发的效率。
内存池的主要结构为:
//ngx_palloc.h
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
;
};
//ngx_core.h
typedef
struct
ngx_pool_s ngx_pool_t
;
typedef
struct
ngx_chain_s ngx_chain_t
;
下面是我简单画的一个图来描述这个结构:
link : http://www.flickr.com/photos/rainx/3765612584/sizes/o/
下面解释一下主要的几个操作:
// 创建内存池
ngx_pool_t
*
ngx_create_pool
(
size_t size
,
ngx_log_t
*
log
);
大致的过程是创建使用 ngx_alloc 分配一个size大小的空间, 然后将 ngx_pool_t* 指向这个空间, 并且初始化里面的成员, 其中
p
->
d
.
last
=
(
u_char
*)
p
+
sizeof
(
ngx_pool_t
);
// 初始指向 ngx_pool_t 结构体后面
p
->
d
.
end
=
(
u_char
*)
p
+
size
;
// 整个结构的结尾后面
p
->
max
=
(
size
<
NGX_MAX_ALLOC_FROM_POOL
)
?
size
:
NGX_MAX_ALLOC_FROM_POOL
;
// 最大不超过 NGX_MAX_ALLOC_FROM_POOL,也就是getpagesize()-1 大小
其他大都设置为null或者0
// 销毁内存池
void
ngx_destroy_pool
(
ngx_pool_t
*
pool
);
遍历链表,所有释放内存,其中如果注册了clenup(也是一个链表结构), 会一次调用clenup 的 handler 进行清理。
// 重置内存池
void
ngx_reset_pool
(
ngx_pool_t
*
pool
);
释放所有large段内存, 并且将d->last指针重新指向 ngx_pool_t 结构之后(和创建时一样)
// 从内存池里分配内存
void
*
ngx_palloc
(
ngx_pool_t
*
pool
,
size_t size
);
void
*
ngx_pnalloc
(
ngx_pool_t
*
pool
,
size_t size
);
void
*
ngx_pcalloc
(
ngx_pool_t
*
pool
,
size_t size
);
void
*
ngx_pmemalign
(
ngx_pool_t
*
pool
,
size_t size
,
size_t alignment
);
ngx_palloc的过程一般为,首先判断待分配的内存是否大于 pool->max的大小,如果大于则使用 ngx_palloc_large 在 large 链表里分配一段内存并返回, 如果小于测尝试从链表的 pool->current 开始遍历链表,尝试找出一个可以分配的内存,当链表里的任何一个节点都无法分配内存的时候,就调用 ngx_palloc_block 生成链表里一个新的节点, 并在新的节点里分配内存并返回, 同时, 还会将pool->current 指针指向新的位置(从链表里面pool->d.failed小于等于4的节点里找出) ,其他几个函数也基本上为 ngx_palloc 的变种,实现方式大同小异
// 释放指定的内存
ngx_int_t ngx_pfree
(
ngx_pool_t
*
pool
,
void
*
p
);
这个操作只有在内存在large链表里注册的内存在会被真正释放,如果分配的是普通的内存,则会在destory_pool的时候统一释放.
// 注册cleanup回叫函数(结构体)
ngx_pool_cleanup_t
*
ngx_pool_cleanup_add
(
ngx_pool_t
*
p
,
size_t size
);
这个过程和我们之前经常使用的有些区别, 他首先在传入的内存池中分配这个结构的空间(包括data段), 然后将为结构体分配的空间返回, 通过操作返回的ngx_pool_cleanup_t结构来添加回叫的实现。 ( 这个过程在nginx里面出现的比较多,也就是 xxxx_add 操作通常不是实际的添加操作,而是分配空间并返回一个指针,后续我们还要通过操作指针指向的空间来实现所谓的add )
下面是内存操作的一些例子 demo/basic_types/mem_op.c
#include
<stdio.h>
#include
"ngx_config.h"
#include
"ngx_conf_file.h"
#include
"nginx.h"
#include
"ngx_core.h"
#include
"ngx_string.h"
#include
"ngx_palloc.h"
volatile
ngx_cycle_t
*
ngx_cycle
;
void
ngx_log_error_core
(
ngx_uint_t level
,
ngx_log_t
*
log
,
ngx_err_t err
,
const
char
*
fmt
,
...)
{
}
typedef
struct
example_s
{
int
a
;
char
*
b
;
}
example_t
;
int
main
()
{
ngx_pool_t
*
pool
;
example_t
*
exp
;
char
*
s
;
pool
=
ngx_create_pool
(
5000
,
NULL
);
printf
(
"available pool regular pool free size is %d now\n"
,
(
ngx_uint_t
)
(
pool
->
d
.
end
-
pool
->
d
.
last
));
exp
=
ngx_palloc
(
pool
,
sizeof
(
example_t
))
;
s
=
ngx_palloc
(
pool
,
sizeof
(
"hello,world"
));
printf
(
"available pool regular pool free size is %d now\n"
,
(
ngx_uint_t
)
(
pool
->
d
.
end
-
pool
->
d
.
last
));
exp
->
a
=
1
;
exp
->
b
=
s
;
strcpy
(
s
,
"hello,world"
);
printf
(
"pool max is %d\n"
,
pool
->
max
);
printf
(
"exp->a is %d, exp->b is %s\n"
,
exp
->
a
,
exp
->
b
);
ngx_destroy_pool
(
pool
);
return
0
;
}
编译运行结果
gcc
-
c
-
O
-
pipe
-
O
-
W
-
Wall
-
Wpointer
-
arith
-
Wno
-
unused
-
parameter
-
Wunused
-
function
-
Wunused
-
variable
-
Wunused
-
value
-
Werror
-
g
-
I
../../../
objs
/
-
I
../../
os
/
unix
/
mem_op
.
c
-
I
../../
core
/
-
I
../../
event
/
-
I
../../
os
/
-
o mem_op
.
o
gcc
-
o mem_op mem_op
.
o
../../../
objs
/
src
/
core
/
ngx_
{
string
,
palloc
}.
o
../../../
objs
/
src
/
os
/
unix
/
ngx_alloc
.
o
-
lcrypt
-
lpcre
-
lcrypto
-
lz
rainx@rainx
-
laptop
:~/
land
/
nginx
-
0.7
.
61
/
src
/
demo
/
basic_types$
./
mem_op
available pool regular pool free size
is
4960
now
available pool regular pool free size
is
4940
now
pool max
is
4960
exp
->
a
is
1
,
exp
->
b
is
hello
,
world

