Nginx内存池实现的了解
参考:
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内存池实现的了解相关推荐
- nginx内存池大小快内存_使用直接内存时可以更快
nginx内存池大小快内存 总览 使用直接内存不能保证提高性能. 考虑到它增加了复杂性,除非有充分的理由使用它,否则应避免使用它. 塞尔吉奥·奥利维拉(Sergio Oliveira Jr)的这篇出色 ...
- 【Nginx 源码学习】内存池 及 优秀案例赏析:Nginx内存池设计
文章目录 关于设计内存池之我的想法 内存池案例 malloc 底层原理 jemalloc && tcmalloc Nginx内存池设计 基础数据结构 源码分析 ngx_create_p ...
- Nginx 内存池似懂非懂?一文带你看清高性能服务器内存池
nginx 内存池 ngx_pool_t nginx 是自己实现了内存池的,所以在nginx ngx_pool_t 这个结构也随处可见,这里主要分析一下内存池的分配逻辑. 内存池实现了包括小块内存.大 ...
- 内存池组件以及根据nginx内存池源码设计实现简易内存池
目录 造轮子内存池原因引入 大量的malloc/free小内存所带来的弊端 弊端 出现场景 大牛解决措施(nginx内存池) 内存池技术 啥叫作内存池技术 内存池技术为啥可以解决上文弊端 高并发内存池 ...
- Nginx 内存池剖析
Nginx 内存池剖析 为什么要使用 Nginx 内存池 传统直接调用内存分配函数的弊端 弊端的解决之道 什么是Nginx 内存池 什么是内存池技术 内存池如何解决弊端 内存池的设计思想 分而治之 N ...
- 这是我见过最详细的Nginx 内存池分析
一,为什么要使用内存池 大多数的解释不外乎提升程序的处理性能及减小内存中的碎片,对于性能优化这点主要体现在: (1)系统的malloc/free等内存申请函数涉及到较多的处理,如申请时合适空间的查找, ...
- Nginx内存池--pool代码抽取(链表套路)
ngx_palloc.c文件 ngx_palloc_large_hm是自己写的代码没有nginx原版的ngx_palloc_large写的好,细节要品味才会发现nginx的美 nginx链表的套路,正 ...
- Nginx源码分析:核心数据结构ngx_cycle_t与内存池概述
nginx源码分析 nginx-1.11.1 参考书籍<深入理解nginx模块开发与架构解析> 核心数据结构与内存池概述 在Nginx中的核心数据结构就是ngx_cycle_t结构,在初始 ...
- nginx内存占用高---内存池使用思考
nginx内存占用高-内存池使用思考 问题现象 nginx top 进程 虚拟内存 200G 实际内存5G 和 CDN 平台相比要高很多 排查思路 使用pmap -p 进程号,发现从系统角度确实 有分 ...
最新文章
- linux mysql 命令 大全
- Python应用实战-在Python中进行数据处理操作的几种方法
- ICMP报文的格式和种类
- 腾讯云搭建WordPress个人博客小白版流程分享
- PM 后台配置TCODE
- 《企业的边界》的书摘
- 员外陪你读论文:DeepWalk: Online learning of Social Representations
- Mysql SQL查询今天、昨天、n天内、第n天(执行效率不高)
- Symbian签名和Uid相关内容的整理(一)
- 第七章:在Spark集群上使用文件中的数据加载成为graph并进行操作(2)
- 机器人枪杀人类的时刻到了
- VB用记录集填充表格函数
- 8_19 比赛总结 [暑假集训]
- 如何有逻辑的,简单清晰的回应问题
- Java线程执行native方法时程序计数器为空,如何确保native执行完后的程序执行的位置
- pert图java_项目管理之甘特图和工程网络图(PERT图)(一)
- mysql主键和唯一索引_主键和唯一索引的区别
- Lumerical官方案例、FDTD时域有限差分法仿真学习(六)——等离子体超材料吸收器(Plasmonic metamaterial absorber)
- Unity 之自动化打包ipa
- 六十星系之54廉贞破军坐卯酉
热门文章
- XPath基本概念(一)
- python 中cookie_详解Python中的Cookie模块使用
- python求无序列表中位数_python 实现在无序数组中找到中位数方法
- hdf heg 批量拼接_[转载]MODIS Aerosol product/MODIS气溶胶产品
- 50k大牛告诉你Python怎么学,10个特性带你快速了解python
- linux的帮助命令及区别,Linux命令及帮助
- XML DOM 加载函数概述
- Linux shell脚本判断服务器网络是否可以上网
- 想学单片机怎么入手?学单片机前先学什么?
- mysql分库分表分页查询语句_MySQL分库分表分库后的查询(8th)