参考:

http://blog.csdn.net/livelylittlefish/article/details/6586946

http://code.google.com/p/nginxsrp/wiki/NginxCodeReview

相关的源码文件为:

- nginx_palloc.h

- nginx_palloc.c

- nginx_alloc.h

- nginx_alloc.c

内存池数据块结构

typedef struct {

u_char *last; // 当前内存池分配到此处,即下一次分配从此处开始

u_char *end; // 内存池结束位置

ngx_pool_t *next; // 内存池里面有很多块内存,这些内存块就是通过该指针连成链表的

ngx_uint_t failed; // 内存池分配失败次数

} ngx_pool_data_t;

内存池结构如下

struct ngx_pool_s {

ngx_pool_data_t d; // 指向内存池的第一个数据块

size_t max; // 内存池数据块的最大值(数目)

ngx_pool_t *current; // 指向当前内存池

ngx_chain_t *chain; // 该指针挂接一个ngx_chain_t结构

ngx_pool_large_t *large; // 大块内存链表,即分配空间超过max的内存

ngx_pool_cleanup_t *cleanup; // 释放内存池的callback

ngx_log_t *log; // 主要用于记录日志信息

};

large内存链表结构

struct ngx_pool_large_s {

ngx_pool_large_t *next; // 指向下一个large内存

void *alloc; // 指向分配的large内存

};

cleanup内存链表结构

struct ngx_pool_cleanup_s {

ngx_pool_cleanup_pt handler; // 指向用于cleanup本cleanup内存

void *data; // 指向分配的cleanup内存

ngx_pool_cleanup_t *next; // 指向下一个cleanup内存

};

创建内存池

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;

}

// 可以看到 last 指向 pool 之后的位置,即下一个pool块分配的位置

p->d.last = (u_char *) p + sizeof(ngx_pool_t);

// end 指向pool的size的最后,即当前pool可容纳的最大尺寸的结束位置

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;

}

注:其中NGX_MAX_ALLOC_FROM_POOL的定义如下:

/*

* NGX_MAX_ALLOC_FROM_POOL should be (ngx_pagesize - 1), i.e. 4095 on x86.

* On Windows NT it decreases a number of locked pages in a kernel.

*/

#define NGX_MAX_ALLOC_FROM_POOL (ngx_pagesize - 1)

而ngx_pagesize的值依赖于OS的,取值如下设置:

ngx_int_t

ngx_os_init(ngx_log_t *log)

{

ngx_uint_t n;

#if (NGX_HAVE_OS_SPECIFIC_INIT)

if (ngx_os_specific_init(log) != NGX_OK) {

return NGX_ERROR;

}

#endif

ngx_init_setproctitle(log);

ngx_pagesize = getpagesize();

ngx_cacheline_size = NGX_CPU_CACHE_LINE;

for (n = ngx_pagesize; n >>= 1; ngx_pagesize_shift++) { /* void */ }

… …

}

其中getpagesize()是由OS提供的。

首先调用ngx_memalign(…)来分配alignedmemory。之后,初始化内存池结构的各个成员,下图为初始化好的内存池的结构图(调用ngx_create_pool(1024,0x80d1c4c)函数):

销毁内存池

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) {

ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0, "free: %p", l->alloc);

if (l->alloc) {

ngx_free(l->alloc);

}

}

#if (NGX_DEBUG)

… …

#endif

for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) {

ngx_free(p);

if (n == NULL) {

break;

}

}

}

遍历内存池链表,释放所有内存,包括pool,large,cleanup链表,如果指定了cleanup回调来释放,则调用cleanup的handler来释放cleanup链表中的内存。

先依次释放pool中cleanup,large类型的链表,最后释放pool本身的链表。

重置内存池

void

ngx_reset_pool(ngx_pool_t *pool)

{

ngx_pool_t *p;

ngx_pool_large_t *l;

// 先遍历large链表,释放large内存

for (l = pool->large; l; l = l->next) {

if (l->alloc) {

ngx_free(l->alloc);

}

}

pool->large = NULL;

for (p = pool; p; p = p->d.next) {

p->d.last = (u_char *) p + sizeof(ngx_pool_t);

}

}

使用ngx_palloc()分配内存

void *

ngx_palloc(ngx_pool_t *pool, size_t size)

{

u_char *m;

ngx_pool_t *p;

if (size <= pool->max) { // 如果需要分配的size大于max,则使用palloc_large来分配

p = pool->current; // 小于max,则从current开始遍历pool链表

do {

// 每次从last处开始分配aligned内存

m = ngx_align_ptr(p->d.last, NGX_ALIGNMENT);

if ((size_t) (p->d.end - m) >= size) {

// 如果分配的内存够用,则就从此处分配,并调整last

p->d.last = m + size;

return m;

}

p = p->d.next;

} while (p);

// 表示链表里没有能够分配size大小的内存节点

// 则生成一个新的节点,并在其中分配内存

return ngx_palloc_block(pool, size);

}

// 大于max的,就在large中进行分配

return ngx_palloc_large(pool, size);

}

下图为在调用ngx_palloc(pool,200)分配200B的内存池物理结构图:

内存池的物理结构

注:文章中的图都摘自

(http://blog.csdn.net/livelylittlefish/article/details/6586946)

转载于:https://blog.51cto.com/quietmadman/1309952

Nginx内存池实现的了解相关推荐

  1. nginx内存池大小快内存_使用直接内存时可以更快

    nginx内存池大小快内存 总览 使用直接内存不能保证提高性能. 考虑到它增加了复杂性,除非有充分的理由使用它,否则应避免使用它. 塞尔吉奥·奥利维拉(Sergio Oliveira Jr)的这篇出色 ...

  2. 【Nginx 源码学习】内存池 及 优秀案例赏析:Nginx内存池设计

    文章目录 关于设计内存池之我的想法 内存池案例 malloc 底层原理 jemalloc && tcmalloc Nginx内存池设计 基础数据结构 源码分析 ngx_create_p ...

  3. Nginx 内存池似懂非懂?一文带你看清高性能服务器内存池

    nginx 内存池 ngx_pool_t nginx 是自己实现了内存池的,所以在nginx ngx_pool_t 这个结构也随处可见,这里主要分析一下内存池的分配逻辑. 内存池实现了包括小块内存.大 ...

  4. 内存池组件以及根据nginx内存池源码设计实现简易内存池

    目录 造轮子内存池原因引入 大量的malloc/free小内存所带来的弊端 弊端 出现场景 大牛解决措施(nginx内存池) 内存池技术 啥叫作内存池技术 内存池技术为啥可以解决上文弊端 高并发内存池 ...

  5. Nginx 内存池剖析

    Nginx 内存池剖析 为什么要使用 Nginx 内存池 传统直接调用内存分配函数的弊端 弊端的解决之道 什么是Nginx 内存池 什么是内存池技术 内存池如何解决弊端 内存池的设计思想 分而治之 N ...

  6. 这是我见过最详细的Nginx 内存池分析

    一,为什么要使用内存池 大多数的解释不外乎提升程序的处理性能及减小内存中的碎片,对于性能优化这点主要体现在: (1)系统的malloc/free等内存申请函数涉及到较多的处理,如申请时合适空间的查找, ...

  7. Nginx内存池--pool代码抽取(链表套路)

    ngx_palloc.c文件 ngx_palloc_large_hm是自己写的代码没有nginx原版的ngx_palloc_large写的好,细节要品味才会发现nginx的美 nginx链表的套路,正 ...

  8. Nginx源码分析:核心数据结构ngx_cycle_t与内存池概述

    nginx源码分析 nginx-1.11.1 参考书籍<深入理解nginx模块开发与架构解析> 核心数据结构与内存池概述 在Nginx中的核心数据结构就是ngx_cycle_t结构,在初始 ...

  9. nginx内存占用高---内存池使用思考

    nginx内存占用高-内存池使用思考 问题现象 nginx top 进程 虚拟内存 200G 实际内存5G 和 CDN 平台相比要高很多 排查思路 使用pmap -p 进程号,发现从系统角度确实 有分 ...

最新文章

  1. linux mysql 命令 大全
  2. Python应用实战-在Python中进行数据处理操作的几种方法
  3. ICMP报文的格式和种类
  4. 腾讯云搭建WordPress个人博客小白版流程分享
  5. PM 后台配置TCODE
  6. 《企业的边界》的书摘
  7. 员外陪你读论文:DeepWalk: Online learning of Social Representations
  8. Mysql SQL查询今天、昨天、n天内、第n天(执行效率不高)
  9. Symbian签名和Uid相关内容的整理(一)
  10. 第七章:在Spark集群上使用文件中的数据加载成为graph并进行操作(2)
  11. 机器人枪杀人类的时刻到了
  12. VB用记录集填充表格函数
  13. 8_19 比赛总结 [暑假集训]
  14. 如何有逻辑的,简单清晰的回应问题
  15. Java线程执行native方法时程序计数器为空,如何确保native执行完后的程序执行的位置
  16. pert图java_项目管理之甘特图和工程网络图(PERT图)(一)
  17. mysql主键和唯一索引_主键和唯一索引的区别
  18. Lumerical官方案例、FDTD时域有限差分法仿真学习(六)——等离子体超材料吸收器(Plasmonic metamaterial absorber)
  19. Unity 之自动化打包ipa
  20. 六十星系之54廉贞破军坐卯酉

热门文章

  1. XPath基本概念(一)
  2. python 中cookie_详解Python中的Cookie模块使用
  3. python求无序列表中位数_python 实现在无序数组中找到中位数方法
  4. hdf heg 批量拼接_[转载]MODIS Aerosol product/MODIS气溶胶产品
  5. 50k大牛告诉你Python怎么学,10个特性带你快速了解python
  6. linux的帮助命令及区别,Linux命令及帮助
  7. XML DOM 加载函数概述
  8. Linux shell脚本判断服务器网络是否可以上网
  9. 想学单片机怎么入手?学单片机前先学什么?
  10. mysql分库分表分页查询语句_MySQL分库分表分库后的查询(8th)