首先看nginx中内存池的示意图
1 内存池结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
|
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; };
|
2 小内存块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
|
typedef struct {
u_char *last;
u_char *end;
ngx_pool_t *next;
ngx_uint_t failed; } ngx_pool_data_t;
|
3 大内存块
1 2 3 4 5 6 7
| struct ngx_pool_large_s { ngx_pool_large_t *next; void *alloc; };
|
4 实例化内存池
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
|
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); 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; }
|
5 内存池分配内存
内存池创建好是为了使用,所以理解源码的最好方式是看内存池是如何分配内存的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
|
void * ngx_palloc(ngx_pool_t *pool, size_t size) { #if !(NGX_DEBUG_PALLOC)
if (size <= pool->max) { return ngx_palloc_small(pool, size, 1); } #endif return ngx_palloc_large(pool, size); }
|
6 小内存块分配内存
6.1 小内存块有足够空间
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
|
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) { 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); }
|
6.2 分配小内存块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
|
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; } }
p->d.next = new;
return m; }
|
7 大内存块分配内存
大内存的管理就简单了,因为内存偏大,大内存一方面使用频率就不高,再者内存宝贵,因此不需要考虑在内存池中的复用
- 需要的时候就向系统申请
- 用完就释放归还给系统
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
|
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; }
|
8 内存池的重置
内存池的意义在于
- 减少系统调用alloc/free系统
- 提高执行效率
- 增加内存的复用
关于复用,本质是内存空间的复用,形式又包括
- 内存池的结构,辛辛苦苦实例化好的内存池结构,用的时候实例化,不用了就销毁也无可厚非,但是如果能一个实例化,多次使用就是对内存的复用
- 内存池中的大内存块复用其结构,真正执行的数据内存区域还是直接根据内核交换,随用随还
- 小内存块通过指针动态管理分配状态,简单移动指针就可以复位/调整内存块分配状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
|
void ngx_reset_pool(ngx_pool_t *pool) { ngx_pool_t *p; ngx_pool_large_t *l;
for (l = pool->large; l; l = l->next) { if (l->alloc) { ngx_free(l->alloc); } }
for (p = pool; p; p = p->d.next) {
p->d.last = (u_char *) p + sizeof(ngx_pool_t); p->d.failed = 0; }
pool->current = pool; pool->chain = NULL; pool->large = NULL; }
|
9 回收内存池
当整个内存池使用完毕需要回收时
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
void ngx_destroy_pool(ngx_pool_t *pool) { ngx_pool_t *p, *n; ngx_pool_large_t *l; ngx_pool_cleanup_t *c;
for (c = pool->cleanup; c; c = c->next) { if (c->handler) { ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0, "run cleanup: %p", c); c->handler(c->data); } }
for (l = pool->large; l; l = l->next) { if (l->alloc) { ngx_free(l->alloc); } }
for (p = pool, n = pool->d.next; ; p = n, n = n->d.next) { ngx_free(p);
if (n == NULL) { break; } } }
|