NGINX(一)内存结构
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(一)内存结构的更多相关文章
- nginx的内存管理
		
先来看内存池的实现,nginx的内存池实现的非常简单. 这里内存池的一些图表可以看老朱同学的slides : http://blog.zhuzhaoyuan.com/2009/09/nginx-int ...
 - Nginx源码研究四:NGINX的内存管理
		
关于nginx的内存使用,我们先看代码,下面是nginx_cycle.c中对全局数据结构cycle的初始化过程 pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, ...
 - Nginx 之 内存池
		
1.基本结构 先来学习一下nginx内存池的几个主要数据结构:[见:./src/core/ngx_palloc.h/.c] ngx_pool_data_t(内存池数据块结构) 1: typed ...
 - Nginx 的进程结构,你明白吗?
		
Nginx 进程结构 这篇文章我们来看下 Nginx 的进程结构,Nginx 其实有两种进程结构: 单进程结构 多进程结构 单进程结构实际上不适用于生产环境,只适合我们做开发调试使用.因为在生产环境中 ...
 - jvm系列(二):JVM内存结构
		
JVM内存结构 所有的Java开发人员可能会遇到这样的困惑?我该为堆内存设置多大空间呢?OutOfMemoryError的异常到底涉及到运行时数据的哪块区域?该怎么解决呢?其实如果你经常解决服务器性能 ...
 - JVM之内存结构
		
JVM是按照运行时数据的存储结构来划分内存结构的.JVM在运行Java程序时,将他们划分成不同格式的数据,分别存储在不同的区域,这些数据就是运行时数据.运行时数据区域包括堆,方法区,运行时常量池,程序 ...
 - Delphi XE7中各种字符串与字符类型的内存结构
		
1. ShortString 类型 定义:type ShortString = string[255]; 内存结构与大小:ShortString 是每个字符为单字节的字符串.ShortString 的 ...
 - Oracle之内存结构(SGA、PGA)
		
一.内存结构 SGA(System Global Area):由所有服务进程和后台进程共享: PGA(Program Global Area):由每个服务进程.后台进程专有:每个进程都有一个PGA. ...
 - UNDO内存结构剖析
		
UNDO内存结构剖析 一.场景 Oracle的 C事物从早上9:00开始读取A表全部10w行数据,这个而读取需要经历5分钟.在9:01的时候,B事物将A表删除100条记录,那么,当9:05的时候,事物 ...
 
随机推荐
- HTML 菜单 a 标签跳转本页面并追加参数
			
代码如下: <!-- BEGIN 追加URL的参数 --> <script type="text/javascript"> function setUrl( ...
 - EXTJS 4.2 资料 控件之tabpanel 静态生成tabpanel
			
//**************页面主体开始***************** var tabpanel = Ext.createWidget('tabpanel', { activeTab: 0, ...
 - qwt 6.1.0集成进Qt creator 2.8.1步骤
			
环境准备与文件编译 ·关于Qt 发现一个Qt正确安装的教程,非常棒!http://www.wikihow.com/Install-Qt-SDK-on-Ubuntu-Linux Qt版本是4.8.5,在 ...
 - springMVC+MyBatis+Spring+maven 整合(1)
			
1.首先第一步.部署mybatis ; 1.1 下载myBatis MyBits前身是iBitis,相对于Hibernate而言,它是半自动化ORM框架.由于老板对性能要求的比较苛刻,不得不放弃我亲爱 ...
 - office安装不了 “windows installer 服务不能更新一个或多个受保护的windows文件”
			
出现这种情况可能是系统中某些文件缺失了,一般发生于安装GHOST版或做过精简的系统 打开C:\WINDOWS\msagent 看看文件夹中内容是不是如下图所示: 再打开C:\Program Files ...
 - 深入js的面向对象学习篇(封装是一门技术和艺术)——温故知新(二)
			
下面全面介绍封装和信息隐藏. 通过将一个方法或属性声明为私用的,可以让对象的实现细节对其它对象保密以降低对象之间的耦合程度,可以保持数据的完整性并对其修改方式加以约束.在代码有许多人参与设计的情况下, ...
 - [转载]Unity3D 访问Access数据库
			
在开始这个小教程之前呢,其实在网上你已经可以找到相关的资料了,但是我还是要把我自己做练习的一点东西分享出来.写这个教程的主要原因呢,是一个朋友在u3d的官网论坛里,找到了这个demo,但是在他使用的过 ...
 - Akka官方文档翻译:Cluster Specification
			
参加了CSDN的一个翻译项目,翻译Akka的文档.CSDN提供的翻译系统不好使,故先排版一下放在博客上. 5.1 集群规范 注意:本文档介绍了集群的设计理念.它分成两部分,第一部分描述了当前已经实现的 ...
 - 简介Java反射基础
			
[参考资料: 疯狂Java讲义 Chapter 18] 1.类加载.连接.初始化 当Java程序需要某一个类时,如果该类尚未加载到内存中,系统会通过加载.连接.初始化三个步骤将该类加载到内存,并完成初 ...
 - 其实,前面倒腾那么多,只是为了想玩SPRING BOOT
			
嘿嘿,,曲线达到.. 看来看来很多国内的速成,都不爽. 官方教程最体贴~~~:) http://docs.spring.io/spring-boot/docs/current/reference/ht ...