本博客( http://blog.csdn.net/livelylittlefish)贴出作者(阿波)相关研究、学习内容所做的笔记,欢迎广大朋友指正!

Content

0.序

1.内存池结构

1.1 ngx_pool_t结构

1.2其他相关结构

1.3 ngx_pool_t的逻辑结构

2.内存池操作

2.1创建内存池

2.2销毁内存池

2.3重置内存池

2.4分配内存

2.4.1 ngx_palloc()函数分析

2.4.2 ngx_palloc_block()函数分析

2.5释放内存

2.6注册cleanup

2.7内存池的物理结构

3.一个例子

3.1代码

3.2如何编译

3.3运行结果

4.小结

5.致谢

0.序

nginx对内存的管理由其自己实现的内存池结构ngx_pool_t来完成,本文重点叙述nginx的内存管理。

nginx内存管理相关文件:

(1) ./src/os/unix/ngx_alloc.h/.c

  • 内存相关的操作,封装了最基本的内存分配函数
  • 如free/malloc/memalign/posix_memalign,分别被封装为ngx_free,ngx_alloc/ngx_calloc, ngx_memalign
    • ngx_alloc:封装malloc分配内存
    • ngx_calloc:封装malloc分配内存,并初始化空间内容为0
    • ngx_memalign:返回基于一个指定alignment的大小为size的内存空间,且其地址为alignment的整数倍,alignment为2的幂。

(2) ./src/core/ngx_palloc.h/.c

  • 封装创建/销毁内存池,从内存池分配空间等函数

.表示nginx-1.0.4代码目录,本文为/usr/src/nginx-1.0.4。

1.内存池结构

nginx对内存的管理均统一完成,例如,在特定的生命周期统一建立内存池(如main函数系统启动初期即分配1024B大小的内存池),需要内存时统一分配内存池中的内存,在适当的时候释放内存池的内存(如关闭http链接时调用ngx_destroy_pool进行销毁)。

因此,开发者只需在需要内存时进行申请即可,不用过多考虑内存的释放等问题,大大提高了开发的效率。先看一下内存池结构。

1.1 ngx_pool_t结构

此处统一一下概念,内存池的数据块:即分配内存在这些数据块中进行,一个内存池可以有多一个内存池数据块。nginx的内存池结构如下。

[cpp] view plain copy
  1. 00048: typedef struct {
  2. 00049:   u_char      *last;  //当前内存池分配到此处,即下一次分配从此处开始
  3. 00050:   u_char      *end;   //内存池结束位置
  4. 00051:   ngx_pool_t  *next;  //内存池里面有很多块内存,这些内存块就是通过该指针连成链表的
  5. 00052:   ngx_uint_t  failed; //内存池分配失败次数
  6. 00053: } ngx_pool_data_t;    //内存池的数据块位置信息
  7. 00054:
  8. 00055:
  9. 00056: struct ngx_pool_s{    //内存池头部结构
  10. 00057:    ngx_pool_data_t     d;       //内存池的数据块
  11. 00058:    size_t              max;     //内存池数据块的最大值
  12. 00059:    ngx_pool_t         *current; //指向当前内存池
  13. 00060:    ngx_chain_t        *chain;   //该指针挂接一个ngx_chain_t结构
  14. 00061:    ngx_pool_large_t   *large;   //大块内存链表,即分配空间超过max的内存
  15. 00062:    ngx_pool_cleanup_t *cleanup; //释放内存池的callback
  16. 00063:    ngx_log_t          *log;     //日志信息
  17. 00064: };

其中,sizeof(ngx_pool_data_t)=16B,sizeof(ngx_pool_t)=40B。
nginx将几乎所有的结构体放在ngx_core.h文件中重新进行了申明,如下。

[cpp] view plain copy
  1. typedef struct ngx_module_s      ngx_module_t;
  2. typedef struct ngx_conf_s        ngx_conf_t;
  3. typedef struct ngx_cycle_s       ngx_cycle_t;
  4. typedef struct ngx_pool_s        ngx_pool_t;
  5. typedef struct ngx_chain_s       ngx_chain_t;
  6. typedef struct ngx_log_s         ngx_log_t;
  7. typedef struct ngx_array_s       ngx_array_t;
  8. typedef struct ngx_open_file_s   ngx_open_file_t;
  9. typedef struct ngx_command_s     ngx_command_t;
  10. typedef struct ngx_file_s        ngx_file_t;
  11. typedef struct ngx_event_s       ngx_event_t;
  12. typedef struct ngx_event_aio_s   ngx_event_aio_t;
  13. typedef struct ngx_connection_s  ngx_connection_t;

1.2其他相关结构

其他与内存池相干的数据结构,如清除资源的cleanup链表,分配的大块内存链表等,如下。

[cpp] view plain copy
  1. 00015: /*
  2. 00016: * NGX_MAX_ALLOC_FROM_POOL should be (ngx_pagesize - 1), i.e. 4095 on x86.
  3. 00017: * On Windows NT it decreases a number of locked pages in a kernel.
  4. 00018: */
  5. 00019: #define NGX_MAX_ALLOC_FROM_POOL (ngx_pagesize - 1)  //在x86体系结构下,该值一般为4096B,即4K
  6. 00020:
  7. 00021: #define NGX_DEFAULT_POOL_SIZE    (16* 1024)
  8. 00022:
  9. 00023: #define NGX_POOL_ALIGNMENT    16
  10. 00024: #define NGX_MIN_POOL_SIZE    \
  11. 00025:    ngx_align((sizeof(ngx_pool_t) + 2 * sizeof(ngx_pool_large_t)),    \
  12. 00026:    NGX_POOL_ALIGNMENT)
  13. 00027:
  14. 00028:
  15. 00029: typedef void (*ngx_pool_cleanup_pt)(void *data);    //cleanup的callback类型
  16. 00030:
  17. 00031: typedef struct ngx_pool_cleanup_s ngx_pool_cleanup_t;
  18. 00032:
  19. 00033: struct ngx_pool_cleanup_s{
  20. 00034:    ngx_pool_cleanup_pt handler;
  21. 00035:    void    *data;              //指向要清除的数据
  22. 00036:    ngx_pool_cleanup_t *next;   //下一个cleanup callback
  23. 00037: };
  24. 00038:
  25. 00039:
  26. 00040: typedef struct ngx_pool_large_s ngx_pool_large_t;
  27. 00041:
  28. 00042: struct ngx_pool_large_s{
  29. 00043:    ngx_pool_large_t  *next;    //指向下一块大块内存
  30. 00044:    void    *alloc;             //指向分配的大块内存
  31. 00045: };
  32. ...
  33. ...
  34. 00067: typedef struct {
  35. 00068:    ngx_fd_t   fd;
  36. 00069:    u_char    *name;
  37. 00070:    ngx_log_t *log;
  38. 00071: } ngx_pool_cleanup_file_t;
  39. 00072:

(gdb) p getpagesize()

$18 = 4096

全局变量ngx_pagesize的初始化是在如下函数中完成的。./src/os/unix/ngx_posix_init.c

[cpp] view plain copy
  1. ngx_int_t
  2. ngx_os_init(ngx_log_t *log)
  3. {
  4. ngx_uint_t  n;
  5. #if (NGX_HAVE_OS_SPECIFIC_INIT)
  6. if (ngx_os_specific_init(log) != NGX_OK) {
  7. return NGX_ERROR;
  8. }
  9. #endif
  10. ngx_init_setproctitle(log);
  11. /** 该函数为glibc的库函数,由系统调用实现,返回内核中的PAGE_SIZE,该值依赖体系结构*/
  12. ngx_pagesize = getpagesize();
  13. ngx_cacheline_size = NGX_CPU_CACHE_LINE;
  14. ...
  15. }

这些数据结构之间的关系,请参考后面的图。

1.3 ngx_pool_t的逻辑结构

这些数据结构逻辑结构图如下。注:本文采用UML的方式画出该图。

2.内存池操作

2.1创建内存池

创建内存池有ngx_create_pool()函数完成,代码如下。

[cpp] view plain copy
  1. 00015: ngx_pool_t *
  2. 00016: ngx_create_pool(size_t size, ngx_log_t *log)
  3. 00017: {
  4. 00018:    ngx_pool_t *p;
  5. 00019:
  6. 00020:    p = ngx_memalign(NGX_POOL_ALIGNMENT, size, log);
  7. 00021:    if (p == NULL) {
  8. 00022:       return NULL;
  9. 00023:    }
  10. 00024:
  11. 00025:    p->d.last = (u_char *) p + sizeof(ngx_pool_t);  //last指向ngx_pool_t结构体之后数据取起始位置
  12. 00026:    p->d.end = (u_char *) p + size;  //end指向分配的整个size大小的内存的末尾
  13. 00027:    p->d.next = NULL;
  14. 00028:    p->d.failed = 0;
  15. 00029:
  16. 00030:    size = size - sizeof(ngx_pool_t);
  17. 00031:    p->max = (size < NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL;  //最大不超过4095B
  18. 00032:
  19. 00033:    p->current = p;
  20. 00034:    p->chain = NULL;
  21. 00035:    p->large = NULL;
  22. 00036:    p->cleanup = NULL;
  23. 00037:    p->log = log;
  24. 00038:
  25. 00039:    return p;
  26. 00040: }

例如,调用ngx_create_pool(1024, 0x80d1c4c)后,创建的内存池物理结构如下图。

2.2销毁内存池

销毁内存池由如下函数完成。

void ngx_destroy_pool(ngx_pool_t *pool)

该函数将遍历内存池链表,所有释放内存,如果注册了clenup(也是一个链表结构),亦将遍历该cleanup链表结构依次调用clenup的handler清理。同时,还将遍历large链表,释放大块内存。

2.3重置内存池

重置内存池由下面的函数完成。

void ngx_reset_pool(ngx_pool_t *pool);

该函数将释放所有large内存,并且将d->last指针重新指向ngx_pool_t结构之后数据区的开始位置,同刚创建后的位置相同。

2.4分配内存

内存分配的函数如下。

void *ngx_palloc(ngx_pool_t *pool, size_t size);

void *ngx_pnalloc(ngx_pool_t *pool, size_t size);

void *ngx_pcalloc(ngx_pool_t *pool, size_t size);

void *ngx_pmemalign(ngx_pool_t *pool, size_t size, size_t alignment);

返回值为分配的内存起始地址。选择其中的两个函数进行分析,其他的也很好理解,省略。

2.4.1 ngx_palloc()函数分析

ngx_palloc()代码如下,分析请参考笔者所加的注释。

[cpp] view plain copy
  1. 00115: void *
  2. 00116: ngx_palloc(ngx_pool_t *pool, size_t size)
  3. 00117: {
  4. 00118:    u_char    *m;
  5. 00119:    ngx_pool_t *p;
  6. 00120:
  7. 00121:    if (size <= pool->max) {//判断待分配内存与max值
  8. 00122:
  9. 00123:       p = pool->current;   //小于max值,则从current节点开始遍历pool链表
  10. 00124:
  11. 00125:       do {
  12. 00126:          m = ngx_align_ptr(p->d.last, NGX_ALIGNMENT);
  13. 00127:
  14. 00128:          if ((size_t) (p->d.end - m) >= size) {
  15. 00129:             p->d.last = m + size;  //在该节点指向的内存块中分配size大小的内存
  16. 00130:
  17. 00131:             return m;
  18. 00132:          }
  19. 00133:
  20. 00134:          p = p->d.next;
  21. 00135:
  22. 00136:       } while (p);
  23. 00137:
  24. 00138:       return ngx_palloc_block(pool, size); //链表里没有能分配size大小内存的节点,则生成一个新的节点并在其中分配内存
  25. 00139:    }
  26. 00140:
  27. 00141:    return ngx_palloc_large(pool, size);  //大于max值,则在large链表里分配内存
  28. 00142: }

例如,在2.1节中创建的内存池中分配200B的内存,调用ngx_palloc(pool, 200)后,该内存池物理结构如下图。

2.4.2 ngx_palloc_block()函数分析

ngx_palloc_block函数代码如下,分析请参考笔者所加的注释。

[cpp] view plain copy
  1. 00175: static void *
  2. 00176: ngx_palloc_block(ngx_pool_t *pool, size_t size)
  3. 00177: {
  4. 00178:    u_char    *m;
  5. 00179:    size_t    psize;
  6. 00180:    ngx_pool_t *p, *new, *current;
  7. 00181:
  8. 00182:    psize = (size_t) (pool->d.end - (u_char *) pool);      //计算pool的大小
  9. 00183:
  10. 00184:    m = ngx_memalign(NGX_POOL_ALIGNMENT, psize, pool->log);//分配一块与pool大小相同的内存
  11. 00185:    if (m == NULL) {
  12. 00186:       return NULL;
  13. 00187:    }
  14. 00188:
  15. 00189:    new = (ngx_pool_t *) m;
  16. 00190:
  17. 00191:    new->d.end = m + psize; //设置end指针
  18. 00192:    new->d.next = NULL;
  19. 00193:    new->d.failed = 0;
  20. 00194:
  21. 00195:    m += sizeof(ngx_pool_data_t); //让m指向该块内存ngx_pool_data_t结构体之后数据区起始位置
  22. 00196:    m = ngx_align_ptr(m, NGX_ALIGNMENT); //按4字节对齐
  23. 00197:    new->d.last = m + size;       //在数据区分配size大小的内存并设置last指针
  24. 00198:
  25. 00199:    current = pool->current;
  26. 00200:
  27. 00201:    for (p = current; p->d.next; p = p->d.next) {
  28. 00202:       if (p->d.failed++ > 4) {   //failed的值只在此处被修改
  29. 00203:          current = p->d.next;    //失败4次以上移动current指针
  30. 00204:       }
  31. 00205:    }
  32. 00206:
  33. 00207:    p->d.next = new;  //将这次分配的内存块new加入该内存池
  34. 00208:
  35. 00209:    pool->current = current ? current : new;
  36. 00210:
  37. 00211:    return m;
  38. 00212: }

注意:该函数分配一块内存后,last指针指向的是ngx_pool_data_t结构体(大小16B)之后数据区的起始位置。而创建内存池时时,last指针指向的是ngx_pool_t结构体(大小40B)之后数据区的起始位置。

结合2.7节的内存池的物理结构,更容易理解。

2.5释放内存

请参考如下函数,不再赘述。

ngx_int_tngx_pfree(ngx_pool_t *pool, void *p)

需要注意的是该函数只释放large链表中注册的内存,普通内存在ngx_destroy_pool中统一释放。

2.6注册cleanup

请参考如下函数,该函数实现也很简单,此处不再赘述。

ngx_pool_cleanup_t *ngx_pool_cleanup_add(ngx_pool_t *p, size_t size)

2.7内存池的物理结构

针对本文第3节的例子,画出的内存池的物理结构如下图。

从该图也能看出2.4节的结论,即内存池第一块内存前40字节为ngx_pool_t结构,后续加入的内存块前16个字节为ngx_pool_data_t结构,这两个结构之后便是真正可以分配内存区域。

因此,本文Reference中的内存分配相关中的图是有一点点小问题的,并不是每一个节点的前面都是ngx_pool_t结构。

3.一个例子

理解并掌握开源软件的最好方式莫过于自己写一些测试代码,或者改写软件本身,并进行调试来进一步理解开源软件的原理和设计方法。本节给出一个创建内存池并从中分配内存的简单例子。

3.1代码

[cpp] view plain copy
  1. /**
  2. * ngx_pool_t test, to test ngx_palloc, ngx_palloc_block, ngx_palloc_large
  3. */
  4. #include <stdio.h>
  5. #include "ngx_config.h"
  6. #include "ngx_conf_file.h"
  7. #include "nginx.h"
  8. #include "ngx_core.h"
  9. #include "ngx_string.h"
  10. #include "ngx_palloc.h"
  11. volatile ngx_cycle_t  *ngx_cycle;
  12. void ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
  13. const char *fmt, ...)
  14. {
  15. }
  16. void dump_pool(ngx_pool_t* pool)
  17. {
  18. while (pool)
  19. {
  20. printf("pool = 0x%x\n", pool);
  21. printf("  .d\n");
  22. printf("    .last = 0x%x\n", pool->d.last);
  23. printf("    .end = 0x%x\n", pool->d.end);
  24. printf("    .next = 0x%x\n", pool->d.next);
  25. printf("    .failed = %d\n", pool->d.failed);
  26. printf("  .max = %d\n", pool->max);
  27. printf("  .current = 0x%x\n", pool->current);
  28. printf("  .chain = 0x%x\n", pool->chain);
  29. printf("  .large = 0x%x\n", pool->large);
  30. printf("  .cleanup = 0x%x\n", pool->cleanup);
  31. printf("  .log = 0x%x\n", pool->log);
  32. printf("available pool memory = %d\n\n", pool->d.end - pool->d.last);
  33. pool = pool->d.next;
  34. }
  35. }
  36. int main()
  37. {
  38. ngx_pool_t *pool;
  39. printf("--------------------------------\n");
  40. printf("create a new pool:\n");
  41. printf("--------------------------------\n");
  42. pool = ngx_create_pool(1024, NULL);
  43. dump_pool(pool);
  44. printf("--------------------------------\n");
  45. printf("alloc block 1 from the pool:\n");
  46. printf("--------------------------------\n");
  47. ngx_palloc(pool, 512);
  48. dump_pool(pool);
  49. printf("--------------------------------\n");
  50. printf("alloc block 2 from the pool:\n");
  51. printf("--------------------------------\n");
  52. ngx_palloc(pool, 512);
  53. dump_pool(pool);
  54. printf("--------------------------------\n");
  55. printf("alloc block 3 from the pool :\n");
  56. printf("--------------------------------\n");
  57. ngx_palloc(pool, 512);
  58. dump_pool(pool);
  59. ngx_destroy_pool(pool);
  60. return 0;
  61. }

3.2如何编译

这个问题是编写测试代码或者改写软件本身最迫切需要解决的问题,否则,编写的代码无从编译或运行,那也无从进行调试并理解软件了。

如何对自己编写的测试代码进行编译,可参考Linux平台代码覆盖率测试-编译过程自动化及对链接的解释、Linux平台如何编译使用Google test写的单元测试?。我们要做的是学习这种编译工程的方法,针对该例子,笔者编写的makefile文件如下。——这便是本节的主要目的。

[plain] view plain copy
  1. CXX = gcc
  2. CXXFLAGS += -g -Wall -Wextra
  3. NGX_ROOT = /usr/src/nginx-1.0.4
  4. TARGETS = ngx_pool_t_test
  5. TARGETS_C_FILE = $(TARGETS).c
  6. CLEANUP = rm -f $(TARGETS) *.o
  7. all: $(TARGETS)
  8. clean:
  9. $(CLEANUP)
  10. CORE_INCS = -I. \
  11. -I$(NGX_ROOT)/src/core \
  12. -I$(NGX_ROOT)/src/event \
  13. -I$(NGX_ROOT)/src/event/modules \
  14. -I$(NGX_ROOT)/src/os/unix \
  15. -I$(NGX_ROOT)/objs \
  16. NGX_PALLOC = $(NGX_ROOT)/objs/src/core/ngx_palloc.o
  17. NGX_STRING = $(NGX_ROOT)/objs/src/core/ngx_string.o
  18. NGX_ALLOC = $(NGX_ROOT)/objs/src/os/unix/ngx_alloc.o
  19. $(TARGETS): $(TARGETS_C_FILE)
  20. $(CXX) $(CXXFLAGS) $(CORE_INCS) $(NGX_PALLOC) $(NGX_STRING) $(NGX_ALLOC) $^ -o $@

3.3运行运行结果

[plain] view plain copy
  1. # ./ngx_pool_t_test
  2. --------------------------------
  3. create a new pool:
  4. --------------------------------
  5. pool = 0x8922020
  6. .d
  7. .last = 0x8922048
  8. .end = 0x8922420
  9. .next = 0x0
  10. .failed = 0
  11. .max = 984
  12. .current = 0x8922020
  13. .chain = 0x0
  14. .large = 0x0
  15. .cleanup = 0x0
  16. .log = 0x0
  17. available pool memory = 984
  18. --------------------------------
  19. alloc block 1 from the pool:
  20. --------------------------------
  21. pool = 0x8922020
  22. .d
  23. .last = 0x8922248
  24. .end = 0x8922420
  25. .next = 0x0
  26. .failed = 0
  27. .max = 984
  28. .current = 0x8922020
  29. .chain = 0x0
  30. .large = 0x0
  31. .cleanup = 0x0
  32. .log = 0x0
  33. available pool memory = 472
  34. --------------------------------
  35. alloc block 2 from the pool:
  36. --------------------------------
  37. pool = 0x8922020
  38. .d
  39. .last = 0x8922248
  40. .end = 0x8922420
  41. .next = 0x8922450
  42. .failed = 0
  43. .max = 984
  44. .current = 0x8922020
  45. .chain = 0x0
  46. .large = 0x0
  47. .cleanup = 0x0
  48. .log = 0x0
  49. available pool memory = 472
  50. pool = 0x8922450
  51. .d
  52. .last = 0x8922660
  53. .end = 0x8922850
  54. .next = 0x0
  55. .failed = 0
  56. .max = 0
  57. .current = 0x0
  58. .chain = 0x0
  59. .large = 0x0
  60. .cleanup = 0x0
  61. .log = 0x0
  62. available pool memory = 496
  63. --------------------------------
  64. alloc block 3 from the pool :
  65. --------------------------------
  66. pool = 0x8922020
  67. .d
  68. .last = 0x8922248
  69. .end = 0x8922420
  70. .next = 0x8922450
  71. .failed = 1
  72. .max = 984
  73. .current = 0x8922020
  74. .chain = 0x0
  75. .large = 0x0
  76. .cleanup = 0x0
  77. .log = 0x0
  78. available pool memory = 472
  79. pool = 0x8922450
  80. .d
  81. .last = 0x8922660
  82. .end = 0x8922850
  83. .next = 0x8922880
  84. .failed = 0
  85. .max = 0
  86. .current = 0x0
  87. .chain = 0x0
  88. .large = 0x0
  89. .cleanup = 0x0
  90. .log = 0x0
  91. available pool memory = 496
  92. pool = 0x8922880
  93. .d
  94. .last = 0x8922a90
  95. .end = 0x8922c80
  96. .next = 0x0
  97. .failed = 0
  98. .max = 0
  99. .current = 0x0
  100. .chain = 0x0
  101. .large = 0x0
  102. .cleanup = 0x0
  103. .log = 0x0
  104. available pool memory = 496

4. 小结

本文针对nginx-1.0.4的内存管理进行了较为全面的分析,包括相关内存池数据结构,内存池的创建、销毁,以及从内存池中分配内存等。最后通过一个简单例子向读者展示nginx内存池的创建和分配操作,同时借此向读者展示编译测试代码的方法。

分析完nginx的内存管理,你一定惊叹于nginx作者的聪明才智。这种内存管理的设计方法小巧、快捷,值得借鉴!

5. 致谢

写作本文,笔者参考了Reference里yixiao的Nginx源码分析-内存池和RainX1982的Nginx代码研究计划。在此给予他们诚挚的感谢!

Reference

man posix_memalign (manual页)(Allocate aligned memory)

man getpagesize (manual页)(Get memory page size)

Nginx源码分析-内存池 (yixiao)

Nginx代码研究计划 (RainX1982)

Appendix: posix_memalign

The  function  posix_memalign()  allocates  size  bytes and places theaddress of the allocated memory in*memptr. The address of the allocated memory will be a multiple of alignment, which must be a  power  oftwo and a multiple of sizeof(void *).

the memory is not zeroed.

posix_memalign() returns zero on success, or one of the error values listed in the next section on failure.  Note that errno is not set.

nginx源码分析—内存池结构ngx_pool_t及内存管理相关推荐

  1. nginx源码分析—内存池结构ngx_pool_t及内存管理(精辟)

    Content 0.序 1.内存池结构 1.1 ngx_pool_t结构 1.2其他相关结构 1.3 ngx_pool_t的逻辑结构 2.内存池操作 2.1创建内存池 2.2销毁内存池 2.3重置内存 ...

  2. Nginx源码分析:核心数据结构ngx_cycle_t与内存池概述

    nginx源码分析 nginx-1.11.1 参考书籍<深入理解nginx模块开发与架构解析> 核心数据结构与内存池概述 在Nginx中的核心数据结构就是ngx_cycle_t结构,在初始 ...

  3. nginx源码分析—数组结构ngx_array_t

    Content 0. 序 1. 数组结构 1.1 ngx_array_t结构 1.2 ngx_array_t的逻辑结构 2. 数组操作 2.1 创建数组 2.2 销毁数组 2.3 添加1个元素 3.  ...

  4. Nginx源码分析-内存池

    本文转自淘宝平台http://www.tbdata.org/archives/1390,不是为了夺他人之美,只是觉得写得很好,怕淘宝万一删掉就找不到了,放在这里保存一下.大家可以直接链接过去,他们那个 ...

  5. nginx源码分析之内存池与线程池丨nginx的多进程网络实现

    nginx源码分析之内存池与线程池 1. nginx的使用场景 2. nginx源码 内存池,线程池,日志 3. nginx的多进程网络实现 视频讲解如下,点击观看: [Linux后台开发系统]ngi ...

  6. Nginx 源码分析-- 模块module 解析执行 nginx.conf 配置文件流程分析 一

    搭建nginx服务器时,主要的配置文件 nginx.conf 是部署和维护服务器人员经常要使用到的文件, 里面进行了许多服务器参数的设置.那么nginx 以模块 module为骨架的设计下是如何运用模 ...

  7. Nginx 源码分析

    1.工程 ngx_conf_file.c ngx_connection.c ngx_cycle.c ngx_file.h ngx_module.c ngx_open_file_cache.h ngx_ ...

  8. Nginx源码分析:启动流程

    nginx源码分析 nginx-1.11.1 参考书籍<深入理解nginx模块开发与架构解析> nginx简介 Nginx的作为服务端软件,表现的主要特点是更快.高扩展.高可靠性.低内存消 ...

  9. Nginx源码分析之 upstream指令

    #Nginx 源码分析 upstream指令 想要的解决问题: 1:upstream存储结构 2:动态 upstream 流程(proxy_pass跟随变量或者域名) 最简单的配置文件 http {u ...

最新文章

  1. Django学习--9 Admin
  2. AWS SDK for Java 2.0 使用的基础入门
  3. hi3531交叉编译环境arm-hisiv100nptl-linux搭建过程
  4. [ 懒人神器 ] —— OO一键build:.zip - .jar
  5. Linux中main和初启函数,ARM启动代码中_main 与用户主程序main()的区别
  6. c语言优先级大全,C语言运算符及其优先级汇总表口诀
  7. android UI 标签
  8. mysql---索引及explain的作用
  9. jdbc预编译插入数据操作
  10. 2345等浏览器主页劫持的解决办法
  11. 【数电】存储器容量的扩展
  12. AADL Inspector 故障树安全分析模块
  13. PyCharm双击打不开怎么办?
  14. Java 快乐练习口算
  15. win7无法打开无线网络服务器,笔记本win7系统无线网络连接受限制或无连接的解决方法...
  16. 如何立即尝试macOS High Sierra Beta
  17. Xpath简介及用法整理
  18. 从Flink SQL doesn't support consuming update and delete changes 错误谈起
  19. 编程语言c24d,可编程控制器RJ71C24-R4FB参考三菱RJ71C24-R4手册 - 广州凌控
  20. c++语言字母转换,c++大小写字母转换的思路有几种?

热门文章

  1. ubuntu1804系统设置在哪里_新风净化系统的风口到底该放在哪里?
  2. jpa 删除是否成功_JPA / Hibernate删除实体有时不起作用
  3. android子view获取父布局,Android获取布局父ID(Android get layout parent id)
  4. 3.分布式文件系统HDFS之二
  5. 第三部分:Idea重构总结
  6. Java 注解详解 (annotation)
  7. 关于Font Awesome图标的使用
  8. 【java开发系列】—— 集合使用方法
  9. Python爬虫入门(8):Beautiful Soup的用法
  10. 为什么C++(感谢waterwalk翻译)