ngx_buf_t和ngx_chain_t是nginx中操作内存的重要手段, 很多的数据都需要通过这个结构进行保存. 其中ngx_buf_t中保存一块可用内存, ngx_chain_t则是将内存块连接起来,组成一个链表, 操作这两个数据结构函数并不多, 下面进行了详解.

基本数据结构

typedef struct ngx_chain_s       ngx_chain_t;
typedef struct ngx_buf_s ngx_buf_t; struct ngx_buf_s {
/*当前读取buffer位置*/
u_char *pos;
/*实际占用buffer的最后位置*/
u_char *last;
/*当前读取文件位置*/
off_t file_pos;
/*文件最后位置*/
off_t file_last; /*buffer开始位置*/
u_char *start;
/*buffer结束位置*/
u_char *end;
/*内存标记*/
ngx_buf_tag_t tag;
/*文件句柄*/
ngx_file_t *file;
ngx_buf_t *shadow; /*1表示内存可以修改*/
unsigned temporary:1;
/*1表示内存不可以修改*/
unsigned memory:1; /*1表示操作内容通过mmap()函数映射不可修改*/
unsigned mmap:1;
/*1表示内存可以回收*/
unsigned recycled:1;
/*1表示操作内容在文件中*/
unsigned in_file:1;
/*1表示立即将内容发送出去*/
unsigned flush:1;
/*1表示立即将内容同步发送出去*/
unsigned sync:1;
/*标记chain是否为最后一块buf*/
unsigned last_buf:1;
/*标记chain中是否为最后一个chain,最后一块buf并不表示是最后一个chain,但最后一个chain一定是最后一块buf*/
unsigned last_in_chain:1; unsigned last_shadow:1;
unsigned temp_file:1; /* STUB */ int num;
}; struct ngx_chain_s {
ngx_buf_t *buf;
ngx_chain_t *next;
};

操作函数

创建一个buf很简单, 直接在内存池中分配一块内存, 然后分配size大小空间, 给ngx_buf_t各个字段进行赋值即可.

ngx_buf_t *
ngx_create_temp_buf(ngx_pool_t *pool, size_t size)
{
ngx_buf_t *b; b = ngx_calloc_buf(pool);
if (b == NULL) {
return NULL;
} b->start = ngx_palloc(pool, size);
if (b->start == NULL) {
return NULL;
} b->pos = b->start;
b->last = b->start;
b->end = b->last + size;
b->temporary = 1; return b;
}

创建一个buf链表节点, 首先检查内存池pool->chain缓存中是否为空, 不为空直接取出使用, 为空重新分配.

ngx_chain_t *
ngx_alloc_chain_link(ngx_pool_t *pool)
{
ngx_chain_t *cl; cl = pool->chain; if (cl) {
pool->chain = cl->next;
return cl;
} cl = ngx_palloc(pool, sizeof(ngx_chain_t));
if (cl == NULL) {
return NULL;
} return cl;
}

直接创建一个ngx_buf_t链表

ngx_chain_t *
ngx_create_chain_of_bufs(ngx_pool_t *pool, ngx_bufs_t *bufs)
{
u_char *p;
ngx_int_t i;
ngx_buf_t *b;
ngx_chain_t *chain, *cl, **ll; /*首先分配所有buf需要的一整块内存, 没有循环分配小内存, 显然为了提高速度, 处处体现了作者对代码质量和性能的要求之高*/
p = ngx_palloc(pool, bufs->num * bufs->size);
if (p == NULL) {
return NULL;
} /*这里用一个二级指针保存第一个节点指针地址, 同样也保存后面节点指针地址, 为什么这么干, 每次保存下上次节点也可以实现,
*这么干少了一次循环内的判断, 否则我们需要判断出第一次循环, 并给chain赋值
*/
ll = &chain; for (i = 0; i < bufs->num; i++) { b = ngx_calloc_buf(pool);
if (b == NULL) {
return NULL;
} b->pos = p;
b->last = p;
b->temporary = 1; b->start = p;
p += bufs->size;
b->end = p; cl = ngx_alloc_chain_link(pool);
if (cl == NULL) {
return NULL;
} cl->buf = b;
/*ll保存的上一个节点指针的指针, 赋值相当于给上一个节点next指针赋值*/
*ll = cl;
/*取本节点next指针地址, 用于下次循环赋值使用*/
ll = &cl->next;
} *ll = NULL; return chain;
}

buf链表添加或者copy, 我觉得这里叫append(附加)可能更好, 因为只是将in链表复制到chain链表后面, 可以看到这里用到了和上面同样的二级指针进行操作.

ngx_int_t
ngx_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain, ngx_chain_t *in)
{
ngx_chain_t *cl, **ll; ll = chain; for (cl = *chain; cl; cl = cl->next) {
ll = &cl->next;
} while (in) {
cl = ngx_alloc_chain_link(pool);
if (cl == NULL) {
return NGX_ERROR;
} cl->buf = in->buf;
*ll = cl;
ll = &cl->next;
in = in->next;
} *ll = NULL; return NGX_OK;
}

更新链表函数功能是回收busy和out链表中闲置资源, 如果tag标志位与传入的一致, 则链表回收到free链表中, 否则直接释放会pool中, 多用于过滤模块

void
ngx_chain_update_chains(ngx_pool_t *p, ngx_chain_t **free, ngx_chain_t **busy,
ngx_chain_t **out, ngx_buf_tag_t tag)
{
ngx_chain_t *cl; if (*busy == NULL) {
*busy = *out; } else {
for (cl = *busy; cl->next; cl = cl->next) { /* void */ } cl->next = *out;
} *out = NULL; while (*busy) {
cl = *busy; if (ngx_buf_size(cl->buf) != 0) {
break;
} if (cl->buf->tag != tag) {
*busy = cl->next;
ngx_free_chain(p, cl);
continue;
} cl->buf->pos = cl->buf->start;
cl->buf->last = cl->buf->start; *busy = cl->next;
cl->next = *free;
*free = cl;
}
}

NGINX(一)内存结构的更多相关文章

  1. nginx的内存管理

    先来看内存池的实现,nginx的内存池实现的非常简单. 这里内存池的一些图表可以看老朱同学的slides : http://blog.zhuzhaoyuan.com/2009/09/nginx-int ...

  2. Nginx源码研究四:NGINX的内存管理

    关于nginx的内存使用,我们先看代码,下面是nginx_cycle.c中对全局数据结构cycle的初始化过程 pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, ...

  3. Nginx 之 内存池

    1.基本结构 先来学习一下nginx内存池的几个主要数据结构:[见:./src/core/ngx_palloc.h/.c]     ngx_pool_data_t(内存池数据块结构) 1: typed ...

  4. Nginx 的进程结构,你明白吗?

    Nginx 进程结构 这篇文章我们来看下 Nginx 的进程结构,Nginx 其实有两种进程结构: 单进程结构 多进程结构 单进程结构实际上不适用于生产环境,只适合我们做开发调试使用.因为在生产环境中 ...

  5. jvm系列(二):JVM内存结构

    JVM内存结构 所有的Java开发人员可能会遇到这样的困惑?我该为堆内存设置多大空间呢?OutOfMemoryError的异常到底涉及到运行时数据的哪块区域?该怎么解决呢?其实如果你经常解决服务器性能 ...

  6. JVM之内存结构

    JVM是按照运行时数据的存储结构来划分内存结构的.JVM在运行Java程序时,将他们划分成不同格式的数据,分别存储在不同的区域,这些数据就是运行时数据.运行时数据区域包括堆,方法区,运行时常量池,程序 ...

  7. Delphi XE7中各种字符串与字符类型的内存结构

    1. ShortString 类型 定义:type ShortString = string[255]; 内存结构与大小:ShortString 是每个字符为单字节的字符串.ShortString 的 ...

  8. Oracle之内存结构(SGA、PGA)

    一.内存结构 SGA(System Global Area):由所有服务进程和后台进程共享: PGA(Program Global Area):由每个服务进程.后台进程专有:每个进程都有一个PGA. ...

  9. UNDO内存结构剖析

    UNDO内存结构剖析 一.场景 Oracle的 C事物从早上9:00开始读取A表全部10w行数据,这个而读取需要经历5分钟.在9:01的时候,B事物将A表删除100条记录,那么,当9:05的时候,事物 ...

随机推荐

  1. EXTJS store 某行某列数据更新等操作

    1.可以使用add(Ext.data.Record[] records)或者add(Ext.data.Record record)向store末尾添加一个或多个record.如: var newRec ...

  2. 【BZOJ 2321】 [BeiJing2011集训]星器

    Description Magic Land上的时间又过了若干世纪…… 现在,人们谈论着一个传说:从前,他们的祖先来到了一个位于东方的岛屿,那里简直就是另外一个世界.善于分析与构造的Magic Lan ...

  3. C#线程同步总结

    对于整数数据类型的简单操作,可以用Interlocked类的成员来实现线程同步.对于复杂的线程同步,有以下几个方法: 1.lock关键字: 2.Monitor: 3.同步事件和等待句柄: 4.Mute ...

  4. Python读写文件 - 转

    http://blog.csdn.net/adupt/article/details/4435615 http://docs.python.org/release/2.5.2/lib/bltin-fi ...

  5. 1202: [HNOI2005]狡猾的商人 - BZOJ

    Description 刁姹接到一个任务,为税务部门调查一位商人的账本,看看账本是不是伪造的.账本上记录了n个月以来的收入情况,其中第i 个月的收入额为Ai(i=1,2,3...n-1,n), .当 ...

  6. RE:转:一些不常用的html代码

    1. oncontextmenu="window.event.returnvalue=false" 将彻底屏蔽鼠标右键<table border oncontextmenu= ...

  7. scrum敏捷开发

    团队PM:袁佩佩 scrum敏捷开发计划制定: 确定项目实施具体阶段目标 确定项目相关任务分解 确定每日站立会议进行计划 确定项目计划总结日程 确定风险解决方案

  8. SSH架构简单总结

    Struts.spring.Hibernate在各层的作用 1)struts 负责 web层.    ActionFormBean 接收网页中表单提交的数据,然后通过Action 进行处理,再Forw ...

  9. Connect to the mysql dataase from remote server

    Make sure that the firewall is closed!!!!!!!!! shell command should be like is: mysql -u username -p ...

  10. eclipse查看jar包中class的中文注释乱码问题的解决

    1,问题来源是在eclipse中直接查看springside的class(由eclipse自动反编译)里面注释的乱码问题: Preferences-General-Workspace-Text fil ...