Mercurial > hg > nginx
diff src/core/ngx_slab.c @ 5718:c46657e391a3
Core: slab allocator free pages defragmentation.
Large allocations from a slab pool result in free page blocks being fragmented,
eventually leading to a situation when no further allocation larger than a page
size are possible from the pool. While this isn't a problem for nginx itself,
it is known to be bad for various 3rd party modules. Fix is to merge adjacent
blocks of free pages in the ngx_slab_free_pages() function.
Prodded by Wandenberg Peixoto and Yichun Zhang.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Tue, 03 Jun 2014 17:53:03 +0400 |
parents | 5024d29354f1 |
children | 25ade23cf281 |
line wrap: on
line diff
--- a/src/core/ngx_slab.c Mon Jun 02 16:16:22 2014 +0400 +++ b/src/core/ngx_slab.c Tue Jun 03 17:53:03 2014 +0400 @@ -129,6 +129,8 @@ pool->pages->slab = pages; } + pool->last = pool->pages + pages; + pool->log_nomem = 1; pool->log_ctx = &pool->zero; pool->zero = '\0'; @@ -626,6 +628,8 @@ if (page->slab >= pages) { if (page->slab > pages) { + page[page->slab - 1].prev = (uintptr_t) &page[pages]; + page[pages].slab = page->slab - pages; page[pages].next = page->next; page[pages].prev = page->prev; @@ -672,7 +676,8 @@ ngx_slab_free_pages(ngx_slab_pool_t *pool, ngx_slab_page_t *page, ngx_uint_t pages) { - ngx_slab_page_t *prev; + ngx_uint_t type; + ngx_slab_page_t *prev, *join; page->slab = pages--; @@ -686,6 +691,59 @@ page->next->prev = page->prev; } + join = page + page->slab; + + if (join < pool->last) { + type = join->prev & NGX_SLAB_PAGE_MASK; + + if (type == NGX_SLAB_PAGE) { + + if (join->next != NULL) { + pages += join->slab; + page->slab += join->slab; + + prev = (ngx_slab_page_t *) (join->prev & ~NGX_SLAB_PAGE_MASK); + prev->next = join->next; + join->next->prev = join->prev; + + join->slab = NGX_SLAB_PAGE_FREE; + join->next = NULL; + join->prev = NGX_SLAB_PAGE; + } + } + } + + if (page > pool->pages) { + join = page - 1; + type = join->prev & NGX_SLAB_PAGE_MASK; + + if (type == NGX_SLAB_PAGE) { + + if (join->slab == NGX_SLAB_PAGE_FREE) { + join = (ngx_slab_page_t *) (join->prev & ~NGX_SLAB_PAGE_MASK); + } + + if (join->next != NULL) { + pages += join->slab; + join->slab += page->slab; + + prev = (ngx_slab_page_t *) (join->prev & ~NGX_SLAB_PAGE_MASK); + prev->next = join->next; + join->next->prev = join->prev; + + page->slab = NGX_SLAB_PAGE_FREE; + page->next = NULL; + page->prev = NGX_SLAB_PAGE; + + page = join; + } + } + } + + if (pages) { + page[pages].prev = (uintptr_t) page; + } + page->prev = (uintptr_t) &pool->free; page->next = pool->free.next;