內存分配相關
系統功能封裝
內存相關的操作主要在 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
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

