/* 设计说明: 当page划分的slot块小于128个字节时候,pre的后两位为NGX_SLAB_SMALL 当page划分的slot块等于128个字节时候,pre的后两位为NGX_SLAB_EXACT 当page划分的slot块大于128个字节时候,pre的后两位为NGX_SLAB_BIG 当page划分的slot块大于2048个字节时候,pre的后两位为NGX_SLAB_PAGE */ #define NGX_SLAB_PAGE_MASK 3 #define NGX_SLAB_PAGE 0 #define NGX_SLAB_BIG 1 #define NGX_SLAB_EXACT 2 #define NGX_SLAB_SMALL 3 #if (NGX_PTR_SIZE == 4) #define NGX_SLAB_PAGE_FREE 0 #define NGX_SLAB_PAGE_BUSY 0xffffffff #define NGX_SLAB_PAGE_START 0x80000000 #define NGX_SLAB_SHIFT_MASK 0x0000000f #define NGX_SLAB_MAP_MASK 0xffff0000 #define NGX_SLAB_MAP_SHIFT 16 #define NGX_SLAB_BUSY 0xffffffff #else /* (NGX_PTR_SIZE == 8) */ #define NGX_SLAB_PAGE_FREE 0 #define NGX_SLAB_PAGE_BUSY 0xffffffffffffffff #define NGX_SLAB_PAGE_START 0x8000000000000000 #define NGX_SLAB_SHIFT_MASK 0x000000000000000f #define NGX_SLAB_MAP_MASK 0xffffffff00000000 #define NGX_SLAB_MAP_SHIFT 32 #define NGX_SLAB_BUSY 0xffffffffffffffff #endif #define ngx_slab_slots(pool) \ (ngx_slab_page_t *) ((u_char *) (pool) + sizeof(ngx_slab_pool_t)) #define ngx_slab_page_type(page) ((page)->prev & NGX_SLAB_PAGE_MASK) #define ngx_slab_page_prev(page) \ (ngx_slab_page_t *) ((page)->prev & ~NGX_SLAB_PAGE_MASK) #define ngx_slab_page_addr(pool, page) \ ((((page) - (pool)->pages) << ngx_pagesize_shift) \ + (uintptr_t) (pool)->start) #if (NGX_DEBUG_MALLOC) #define ngx_slab_junk(p, size) ngx_memset(p, 0xA5, size) #elif (NGX_HAVE_DEBUG_MALLOC) #define ngx_slab_junk(p, size) \ if (ngx_debug_malloc) ngx_memset(p, 0xA5, size) #else #define ngx_slab_junk(p, size) #endif static ngx_slab_page_t *ngx_slab_alloc_pages(ngx_slab_pool_t *pool, ngx_uint_t pages); static void ngx_slab_free_pages(ngx_slab_pool_t *pool, ngx_slab_page_t *page, ngx_uint_t pages); static void ngx_slab_error(ngx_slab_pool_t *pool, ngx_uint_t level, char *text); static ngx_uint_t ngx_slab_max_size; static ngx_uint_t ngx_slab_exact_size; static ngx_uint_t ngx_slab_exact_shift; void ngx_slab_sizes_init(void) { ngx_uint_t n; /* 知识补充: 32位机器上,ngx_pagesize一般为4096字节 */ /* 设计说明: ngx_slab_max_size 2048字节 ngx_slab_exact_size 128字节 ngx_slab_exact_shift 7 ngx_slab_exact_size对应的页偏移量,4096对应的偏移量是12 */ ngx_slab_max_size = ngx_pagesize / 2; ngx_slab_exact_size = ngx_pagesize / (8 * sizeof(uintptr_t)); for (n = ngx_slab_exact_size; n >>= 1; ngx_slab_exact_shift++) { /* void */ } } void ngx_slab_init(ngx_slab_pool_t *pool) { u_char *p; size_t size; ngx_int_t m; ngx_uint_t i, n, pages; ngx_slab_page_t *slots, *page; // 设置可以分配的最小字节数,pool->min_shift默认是3,即pool->min_size = 8 pool->min_size = (size_t) 1 << pool->min_shift; // 获取slot相对地址 slots = ngx_slab_slots(pool); p = (u_char *) slots; // 获取slab池子大小 size = pool->end - p; // 初始化数据(没啥意义) ngx_slab_junk(p, size); /* 设计说明: ngx_pagesize_shift 是页偏移量,4096字节的偏移量是12 */ n = ngx_pagesize_shift - pool->min_shift; /* 设计说明: slot 一般只用来标记 8 16 32 64 128 256 512 1024 2048 一个9个 */ for (i = 0; i < n; i++) { /* only "next" is used in list head */ slots[i].slab = 0; slots[i].next = &slots[i]; slots[i].prev = 0; } // 跳过slot列表 p += n * sizeof(ngx_slab_page_t); // 设置slab池状态 pool->stats = (ngx_slab_stat_t *) p; ngx_memzero(pool->stats, n * sizeof(ngx_slab_stat_t)); // 跳过stats列表 p += n * sizeof(ngx_slab_stat_t); // 更新size,刨除 slots+stats size -= n * (sizeof(ngx_slab_page_t) + sizeof(ngx_slab_stat_t)); // 计算剩余页数 pages = (ngx_uint_t) (size / (ngx_pagesize + sizeof(ngx_slab_page_t))); pool->pages = (ngx_slab_page_t *) p; ngx_memzero(pool->pages, pages * sizeof(ngx_slab_page_t)); // 页数据 page = pool->pages; /* only "next" is used in list head */ pool->free.slab = 0; pool->free.next = page; pool->free.prev = 0; // 记录可以分配的页数目 page->slab = pages; page->next = &pool->free; page->prev = (uintptr_t) &pool->free; // 设置起始点(字节对齐) pool->start = ngx_align_ptr(p + pages * sizeof(ngx_slab_page_t), ngx_pagesize); /* 设计说明: 因为字节对齐,会浪费一定的内存空间,因此需要重新计算pages */ m = pages - (pool->end - pool->start) / ngx_pagesize; if (m > 0) { pages -= m; page->slab = pages; } // 设置slab池的末尾节点 pool->last = pool->pages + pages; pool->pfree = pages; pool->log_nomem = 1; pool->log_ctx = &pool->zero; pool->zero = '\0'; }