mirror of
https://github.com/nginx/nginx.git
synced 2024-12-03 04:39:00 +08:00
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.
This commit is contained in:
parent
9b5a17b5e2
commit
afb4aafc6e
@ -129,6 +129,8 @@ ngx_slab_init(ngx_slab_pool_t *pool)
|
|||||||
pool->pages->slab = pages;
|
pool->pages->slab = pages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pool->last = pool->pages + pages;
|
||||||
|
|
||||||
pool->log_nomem = 1;
|
pool->log_nomem = 1;
|
||||||
pool->log_ctx = &pool->zero;
|
pool->log_ctx = &pool->zero;
|
||||||
pool->zero = '\0';
|
pool->zero = '\0';
|
||||||
@ -626,6 +628,8 @@ ngx_slab_alloc_pages(ngx_slab_pool_t *pool, ngx_uint_t pages)
|
|||||||
if (page->slab >= pages) {
|
if (page->slab >= pages) {
|
||||||
|
|
||||||
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].slab = page->slab - pages;
|
||||||
page[pages].next = page->next;
|
page[pages].next = page->next;
|
||||||
page[pages].prev = page->prev;
|
page[pages].prev = page->prev;
|
||||||
@ -672,7 +676,8 @@ static void
|
|||||||
ngx_slab_free_pages(ngx_slab_pool_t *pool, ngx_slab_page_t *page,
|
ngx_slab_free_pages(ngx_slab_pool_t *pool, ngx_slab_page_t *page,
|
||||||
ngx_uint_t pages)
|
ngx_uint_t pages)
|
||||||
{
|
{
|
||||||
ngx_slab_page_t *prev;
|
ngx_uint_t type;
|
||||||
|
ngx_slab_page_t *prev, *join;
|
||||||
|
|
||||||
page->slab = pages--;
|
page->slab = pages--;
|
||||||
|
|
||||||
@ -686,6 +691,59 @@ ngx_slab_free_pages(ngx_slab_pool_t *pool, ngx_slab_page_t *page,
|
|||||||
page->next->prev = page->prev;
|
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->prev = (uintptr_t) &pool->free;
|
||||||
page->next = pool->free.next;
|
page->next = pool->free.next;
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ typedef struct {
|
|||||||
size_t min_shift;
|
size_t min_shift;
|
||||||
|
|
||||||
ngx_slab_page_t *pages;
|
ngx_slab_page_t *pages;
|
||||||
|
ngx_slab_page_t *last;
|
||||||
ngx_slab_page_t free;
|
ngx_slab_page_t free;
|
||||||
|
|
||||||
u_char *start;
|
u_char *start;
|
||||||
|
Loading…
Reference in New Issue
Block a user