1.引言
如果你开发过Nginx第三方模块,会发现虽然我们在写C语言的代码,但是我们不需要关系内存的释放.
如果你现在配置一些比较罕见的Nginx使用场景的配置,你可能需要去修改Nginx在请求和连接上初始
分配的内存池的大小,但是Nginx官方上通过会写着不要去改这样的配置,究竟要不要改呢?
2.内存池的意义
struct ngx_connection_s中的ngx_pool_t* pool,
这个成员变量表示着这个连接对应的内存池,可通过connection_pool_size进行配置,
为什么需要内存池呢?
如果我们有一些工具的话可以发现,Nginx产生的内存碎片是非常小的,
这个就是内存池的一些功劳,内存池会把内存提前分配好一批.
当我们使用小块内存的时候,会通过next指针将小块内存一个一个连接在一起,大大减少了内存碎片.
对于大块内存,还是会通过操作系统的alloc去分配大块内存.
对于Nginx,内存池有什么好处呢?
因为Nginx主要在处理外部请求,外部请求特别对于http请求会有两个非常明显的特点,
(1)每当我们有一个tcp连接的时候,这个连接上面可能会有很多http请求.
这个就是我们所说的http-keep-alive请求,连接没有关闭,执行完一条请求以后,还负责执行另外
一条请求,一些内存为连接分配一次就够了,比如说,去读取每个请求的前1K字节,那么在连接内存
池上分配一次,只要这个连接不关闭,那么这个1K的内存永远都不需要释放,什么时候才需要释放呢?
连接关闭的时候再释放是没有任何问题的.
(2)请求内存池,每个http请求开始分配的时候不知道分配多大.
对于http请求特别是http1.1通常会分配4K大小的内存,因为我们的url和header往往需要分配这么多,
如果没有内存池,我们可能需要频繁小块地分配内存,而分配内存是有代价的,如果我们一次性分配
较多内存就没有这样的问题,请求执行完毕以后,哪怕连接还可以复用,我们可以把请求池销毁,而这样
所有Nginx第三方模块开发者就不必关注内存什么时候被释放,只要关注是从请求内存池中申请分配的
内存还是从连接内存池中申请分配的内存,只要这个逻辑上讲得通,比如说请求结束以后,连接仍然想继
续使用,可以在连接内存池中进行分配.
每一个连接的内存池大小:
http://nginx.org/en/docs/http/ngx_http_core_module.html#connection_pool_size
Syntax: connection_pool_size size;
Default: connection_pool_size 256|512;
Context: http, server
Allows accurate tuning of per-connection memory allocations. This directive
has minimal impact on performance and should not generally be used. By default,
the size is equal to 256 bytes on 32-bit platforms and 512 bytes on 64-bit platforms.
Prior to version 1.9.8, the default value was 256 on all platforms.
这里的256|512只是内存池预分配的大小,并不是说我们的内存就只能分配这么大,这个只是为了
我们之后分配内存的次数.
每一个请求的内存池的大小:
http://nginx.org/en/docs/http/ngx_http_core_module.html#request_pool_size
Syntax: request_pool_size size;
Default: request_pool_size 4k;
Context: http, server
Allows accurate tuning of per-request memory allocations. This directive has
minimal impact on performance and should not generally be used.
默认大小是4K,为什么和请求的内存池的大小差距那么大呢?8倍.
因为对于连接而言,它需要保存的上下文的信息特别少,只需要帮助后面的请求读取
最初一部分字节就可以了.但是对于请求而言,我们需要保存大量的上下文信息,比如说
所有读取到的url,header等需要一直保存下来.url通常还比较长.官方文档说它对性能
影响比较小,在极端场景下,如果url特别大,可以考虑把request_pool_size分配地更大,
通常url,header比较小的时候,可以考虑把request_pool_size配置小一些,这样可以消耗
更小地内存,方便Nginx做更大并发量的请求.
以上是内存池的原理和请求内存池连接内存池的配置代表着怎样的意义,内存池对于减少
我们的内存碎片和第三方模块的快速开发具有很大的意义.
在开发第三方模块的时候,会不正确地使用内存池,比如本该在请求内存池中分配内存却
到连接内存池中分配内存了,这会导致内存的延期是否,导致Nginx内存无畏地增加,这个
需要我们的注意.
介绍一下Nginx的http核心模块的配置参数结构体ngx_http_core_srv_conf_t:
/home/muten/module/nginx-1.13.7/src/http/ngx_http_core_module.h
typedef struct {
/* array of the ngx_http_server_name_t, "server_name" directive */
ngx_array_t server_names;
/* server ctx */
ngx_http_conf_ctx_t *ctx;
ngx_str_t server_name;
size_t connection_pool_size;
size_t request_pool_size;
size_t client_header_buffer_size;
ngx_bufs_t large_client_header_buffers;
ngx_msec_t client_header_timeout;
ngx_flag_t ignore_invalid_headers;
ngx_flag_t merge_slashes;
ngx_flag_t underscores_in_headers;
unsigned listen:1;
#if (NGX_PCRE)
unsigned captures:1;
#endif
ngx_http_core_loc_conf_t **named_locations;
} ngx_http_core_srv_conf_t;
3.内存池的分类与管理
4.C语言中的内存分配方式
void free();
void* malloc();
void* calloc();
void* realloc();
#include <stdlib.h>
int posix_memalign(void **memptr, size_t alignment, size_t size);
void *aligned_alloc(size_t alignment, size_t size);
void *valloc(size_t size);
#include <malloc.h>
void *memalign(size_t alignment, size_t size);
void *pvalloc(size_t size);