Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2321014
  • 博文数量: 252
  • 博客积分: 5472
  • 博客等级: 大校
  • 技术积分: 3107
  • 用 户 组: 普通用户
  • 注册时间: 2011-09-17 18:39
文章分类

全部博文(252)

文章存档

2012年(96)

2011年(156)

分类: LINUX

2012-03-15 14:20:29

内存分配相关
系统功能封装

内存相关的操作主要在 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会在适当的时候释放内存池的资源,开发者只要在需要的时候对内存进行申请即可,不用过多考虑内存的释放等问题,大大提高了开发的效率。

内存池的主要结构为:


  1. //ngx_palloc.h
  2. struct ngx_pool_s {
  3. ngx_pool_data_t d;
  4. size_t max;
  5. ngx_pool_t *current;
  6. ngx_chain_t *chain;
  7. ngx_pool_large_t *large;
  8. ngx_pool_cleanup_t *cleanup;
  9. ngx_log_t *log;
  10. };
  11. //ngx_core.h
  12. typedef struct ngx_pool_s ngx_pool_t;
  13. typedef struct ngx_chain_s ngx_chain_t;

下面是我简单画的一个图来描述这个结构:


下面解释一下主要的几个操作:


  1. // 创建内存池
  2. ngx_pool_t *ngx_create_pool(size_t size, ngx_log_t *log);
  3. 大致的过程是创建使用 ngx_alloc 分配一个size大小的空间, 然后将 ngx_pool_t* 指向这个空间, 并且初始化里面的成员, 其中
  4. p->d.last = (u_char *) p + sizeof(ngx_pool_t); // 初始指向 ngx_pool_t 结构体后面
  5. p->d.end = (u_char *) p + size; // 整个结构的结尾后面
  6. p->max = (size < NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL; // 最大不超过 NGX_MAX_ALLOC_FROM_POOL,也就是getpagesize()-1 大小

其他大都设置为null或者0


  1. // 销毁内存池
  2. void ngx_destroy_pool(ngx_pool_t *pool);

遍历链表,所有释放内存,其中如果注册了clenup(也是一个链表结构), 会一次调用clenup 的 handler 进行清理。


  1. // 重置内存池
  2. void ngx_reset_pool(ngx_pool_t *pool);

释放所有large段内存, 并且将d->last指针重新指向 ngx_pool_t 结构之后(和创建时一样)


  1. // 从内存池里分配内存
  2. void *ngx_palloc(ngx_pool_t *pool, size_t size);
  3. void *ngx_pnalloc(ngx_pool_t *pool, size_t size);
  4. void *ngx_pcalloc(ngx_pool_t *pool, size_t size);
  5. 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 的变种,实现方式大同小异


  1. // 释放指定的内存
  2. ngx_int_t ngx_pfree(ngx_pool_t *pool, void *p);

这个操作只有在内存在large链表里注册的内存在会被真正释放,如果分配的是普通的内存,则会在destory_pool的时候统一释放.


  1. // 注册cleanup回叫函数(结构体)
  2. 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


  1. #include
  2. #include "ngx_config.h"
  3. #include "ngx_conf_file.h"
  4. #include "nginx.h"
  5. #include "ngx_core.h"
  6. #include "ngx_string.h"
  7. #include "ngx_palloc.h"
  8. volatile ngx_cycle_t *ngx_cycle;
  9. void
  10. ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
  11. const char *fmt, ...)
  12. {
  13. }
  14. typedef struct example_s {
  15. int a;
  16. char* b;
  17. } example_t;
  18. int main()
  19. {
  20. ngx_pool_t *pool;
  21. example_t* exp;
  22. char* s;
  23. pool = ngx_create_pool(5000, NULL);
  24. printf("available pool regular pool free size is %d now\n", (ngx_uint_t) (pool->d.end - pool->d.last));
  25. exp = ngx_palloc(pool, sizeof(example_t)) ;
  26. s = ngx_palloc(pool, sizeof("hello,world"));
  27. printf("available pool regular pool free size is %d now\n", (ngx_uint_t) (pool->d.end - pool->d.last));
  28. exp->a = 1;
  29. exp->b = s;
  30. strcpy(s, "hello,world");
  31. printf("pool max is %d\n", pool->max);
  32. printf("exp->a is %d, exp->b is %s\n", exp->a, exp->b);
  33. ngx_destroy_pool(pool);
  34. return 0;
  35. }
编译
  1. 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
  2. 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

运行
  1. $ ./mem_op
显示结果

  1. available pool regular pool free size is 4960 now
  2. available pool regular pool free size is 4940 now
  3. pool max is 4960
  4. exp->a is 1, exp->b is hello,world

阅读(1743) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~