浅谈nginx内存池(四)
Nginx的缓冲区设计也是非常灵活的:
(1)可以自定义管理业务层面的缓冲区链表。
(2)可以将空闲的缓冲区链表交还给内存池pool->chain结构。
缓冲区ngx_buf_t是nginx处理大数据的关键数据结构,他既应用于内存数据,也应用于磁盘数据。
下面就是关于nginx中buf的实现
---------->buf分为两种类型:
(1)一种是file;
(2)一种是memory;
我们发送往套接字或者其他的设备发送东西时,我们是先将数据放大buf中,然后当设备或者套接字准备好了,我们就会从buf中读取。
ngx_buf_s具体结构如下:
struct ngx_buf_s {
u_char *pos;//待处理数据的开始标记(表示已经执行的数据的位置)
///last和上面内存池中last一样,也就是使用的内存的最后一个字节的指针
u_char *last;//待处理数据的结尾标记
///文件指针(处理文件时,待处理文件的开始标记和结尾标记)
off_t file_pos;
off_t file_last;
///buf的开始指针(缓冲区开始的指针地址和缓冲区结尾的指针地址)
u_char *start; /* start of buffer */
u_char *end; /* end of buffer */
///这里表示这个buf从属于那个模块。
ngx_buf_tag_t tag;//缓冲区标记地址,是一个void*的指针
ngx_file_t *file;//引用的文件
ngx_buf_t *shadow;
///一些标记
/* the buf's content could be changed */
unsigned temporary:1; //标志位,为1时,可修改
///在内存中是不能改变的。
unsigned memory:1; //标志位,为1时,内存只读
///是否是mmap的内存
unsigned mmap:1; //标志位,为1时,mmap映射过来的内存不可修改
unsigned recycled:1; //标志位,为1时,可回收
///一些标志位
unsigned in_file:1; //标志位,为1时,表示处理的是文件
unsigned flush:1; //标志位,为1时,表示需要进行fflush操作
unsigned sync:1; //标志位,为1时,表示可以进行同步操作,容易引起堵塞
unsigned last_buf:1;//标志位,为1时,表示缓冲区链表ngx_chain_t上的最后一块待处理缓冲区
unsigned last_in_chain:1; //标志位,为1时,表示为缓冲区链表ngx_chain_t上的最后一块缓冲区
unsigned last_shadow:1; //标志位,为1时,表示是否是最后一个影子缓冲区
unsigned temp_file:1; //标志位,为1时,表示当前缓冲区是否属于临时文件
int num;
};
说明:
(1)从这个数据结构中,可以看出ngx_buf_s结构,既可以处理内存,也可以数据文件。
(2)Nginx使用了位域的方法,节省存储空间。
(3)每个buf都记录了开始和结束点以及未处理的开始和结束点,因为缓冲区的内存申请了之后,是可以被复用的。
(4)所有缓冲区需要的数据结构以及缓冲区的buf内存块都会被分配到内存池上面。
如图:
(1)nginx的缓冲区数据结构主要包含了链表数据结构ngx_chain_t和buf数据结构ngx_buf_s。
(2)nginx可以在自定义的业务层面管理繁忙busy和空闲free的缓冲区链表结构,可以对缓冲区的链表结构和buf结构进行管理。
(3)如果缓冲区链表需要被回收,则会放到nginx内存池的pool->chain链表上。
(4)缓冲区是nginx用的非常多的一种数据结构,主要用于接收和输出HTTP的数据信息,所以对nginx的缓冲区的数据结构深入理解非常有必要。
下面就可以看看我们之前在ngx_pool_t中没有说明的一个结构--->ngx_chain_t:
缓冲区链表结构 ngx_chain_t
typedef struct ngx_chain_s ngx_chain_t;
/*
* 缓冲区链表结构,放在pool内存池上面
*/
struct ngx_chain_s {
ngx_buf_t *buf;
ngx_chain_t *next;
};
1. 是否还记得内存池结构中,有一个数据结构pool->chain就是保存空闲的缓冲区链表的。
2. Nginx的缓冲区ngx_buf_t,通过ngx_chain_t链表结构进行关联和管理。
3. 通过链表的方式实现buf有一个非常大的好处:如果一次需要缓冲区的内存很大,那么并不需要分配一块完整的内存,只需要将缓冲区串起来就可以了。
2.接下来我们来看看如何创建一个buf,在nginx中一般都是调用ngx_create_temp_buf来创建buf。函数也比较简单,就是从pool中分配内存然后初始化相关域。
具体代码如下:
ngx_buf_t * ngx_create_temp_buf(ngx_pool_t *pool, size_t size)
{
ngx_buf_t *b;
///calloc一个buf,可以看到它调用的是calloc,也就是说都会清0.
b = ngx_calloc_buf(pool);
if (b == NULL) {
return NULL;
}
///然后从内存池中分配一块内存。并将这块内存链接到b->start.
b->start = ngx_palloc(pool, size);
/*
最终调用的是内存池pool,开辟一段内存用作缓冲区,主要放置ngx_buf_t 结构体:
//set by ngx_calloc_buf():
* b->file_pos = 0;
* b->file_last = 0;
* b->file = NULL;
* b->shadow = NULL;
* b->tag = 0;
* and flags
*/
if (b->start == NULL) {
return NULL;
}
///设置相关的域。
b->pos = b->start;
b->last = b->start;
///设置打消
b->end = b->last + size;
b->temporary = 1;
return b;
}