访问这里,获取更多原创内容。函数
说明:本系列的文章基于Nginx-1.5.0版本代码。布局
在上一篇”基于块的内存释放“中,咱们已经见过一个函数:学习
static void ngx_slab_free_pages(ngx_slab_pool_t *pool, ngx_slab_page_t *page, ngx_uint_t pages);
单从名字应该就已经可以猜到这个函数的做用了,没错,就是本篇的主题 --- ”基于页的内存释放“,当释放的内存类型为”NGX_SLAB_PAGE“,或者与待释放的内存块所对应的页已经彻底释放时,就到了这个函数大显身手的时候了,但它的内容却只有短短的十几行代码:ui
static void ngx_slab_free_pages(ngx_slab_pool_t *pool, ngx_slab_page_t *page, ngx_uint_t pages) { ngx_slab_page_t *prev; page->slab = pages--; /*若是待释放的内存空间不止一页,则须要将后续的页管理单元恢复为初始化状态*/ if (pages) { ngx_memzero(&page[1], pages * sizeof(ngx_slab_page_t)); } /*根据前面几篇的内容能够知道,当页内存管理单元挂接在slot分级链表下时,page->next是不为空的,这时须要先将其从链表中摘除*/ if (page->next) { prev = (ngx_slab_page_t *) (page->prev & ~NGX_SLAB_PAGE_MASK); prev->next = page->next; page->next->prev = page->prev; } /*将待释放的空闲页管理单元挂接到free链表的首部,但这里并无作额外的合并动做*/ page->prev = (uintptr_t) &pool->free; page->next = pool->free.next; page->next->prev = (uintptr_t) page; pool->free.next = page; }
这里咱们以第二篇“基于页的内存分配”中的最后一幅图所描述的场景为例,也就是说在初始化以后相继分配了m0页,1页,m1页,1页,而后咱们来释放掉中间的m1页,这时的内存布局就变成了以下的形式:spa
这里须要指出的是,ngx_slab_free_pages()函数只是将待释放的内存页管理单元从新挂接到了free链表的首部,而没有尝试进行合并,因此当程序运行一段时间后你可能会发现空闲的内存明明还有不少,但大块的内存申请老是会返回错误,就是由于内存被碎片化了,没有知足要求的连续内存段能够分配了。这个问题在更新的版本中不知道有没有改进。.net
除此以外还有一种状况就是:当待释放的内存页是用于小块内存分配时,调用ngx_slab_free_pages()函数时对应的页内存管理单元还挂接在slot分级链表下,这时须要先将页内存管理单元从slot分级链表中摘除,而后再挂接到free空闲页链表中。code
若是你看到这里了,那么Nginx slab内存管理相关内容的学习应该也告一段落了,这个系列的文章中加入了很多内存布局图,目的就在于更加清楚直观地展示出内存分配和释放这些动态过程当中的各个细节,方便你们理解。blog
但愿这个系列的文章可以对你有帮助。内存