comparison 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
comparison
equal deleted inserted replaced
5717:efc84a5723b3 5718:c46657e391a3
127 if (m > 0) { 127 if (m > 0) {
128 pages -= m; 128 pages -= m;
129 pool->pages->slab = pages; 129 pool->pages->slab = pages;
130 } 130 }
131 131
132 pool->last = pool->pages + pages;
133
132 pool->log_nomem = 1; 134 pool->log_nomem = 1;
133 pool->log_ctx = &pool->zero; 135 pool->log_ctx = &pool->zero;
134 pool->zero = '\0'; 136 pool->zero = '\0';
135 } 137 }
136 138
624 for (page = pool->free.next; page != &pool->free; page = page->next) { 626 for (page = pool->free.next; page != &pool->free; page = page->next) {
625 627
626 if (page->slab >= pages) { 628 if (page->slab >= pages) {
627 629
628 if (page->slab > pages) { 630 if (page->slab > pages) {
631 page[page->slab - 1].prev = (uintptr_t) &page[pages];
632
629 page[pages].slab = page->slab - pages; 633 page[pages].slab = page->slab - pages;
630 page[pages].next = page->next; 634 page[pages].next = page->next;
631 page[pages].prev = page->prev; 635 page[pages].prev = page->prev;
632 636
633 p = (ngx_slab_page_t *) page->prev; 637 p = (ngx_slab_page_t *) page->prev;
670 674
671 static void 675 static void
672 ngx_slab_free_pages(ngx_slab_pool_t *pool, ngx_slab_page_t *page, 676 ngx_slab_free_pages(ngx_slab_pool_t *pool, ngx_slab_page_t *page,
673 ngx_uint_t pages) 677 ngx_uint_t pages)
674 { 678 {
675 ngx_slab_page_t *prev; 679 ngx_uint_t type;
680 ngx_slab_page_t *prev, *join;
676 681
677 page->slab = pages--; 682 page->slab = pages--;
678 683
679 if (pages) { 684 if (pages) {
680 ngx_memzero(&page[1], pages * sizeof(ngx_slab_page_t)); 685 ngx_memzero(&page[1], pages * sizeof(ngx_slab_page_t));
682 687
683 if (page->next) { 688 if (page->next) {
684 prev = (ngx_slab_page_t *) (page->prev & ~NGX_SLAB_PAGE_MASK); 689 prev = (ngx_slab_page_t *) (page->prev & ~NGX_SLAB_PAGE_MASK);
685 prev->next = page->next; 690 prev->next = page->next;
686 page->next->prev = page->prev; 691 page->next->prev = page->prev;
692 }
693
694 join = page + page->slab;
695
696 if (join < pool->last) {
697 type = join->prev & NGX_SLAB_PAGE_MASK;
698
699 if (type == NGX_SLAB_PAGE) {
700
701 if (join->next != NULL) {
702 pages += join->slab;
703 page->slab += join->slab;
704
705 prev = (ngx_slab_page_t *) (join->prev & ~NGX_SLAB_PAGE_MASK);
706 prev->next = join->next;
707 join->next->prev = join->prev;
708
709 join->slab = NGX_SLAB_PAGE_FREE;
710 join->next = NULL;
711 join->prev = NGX_SLAB_PAGE;
712 }
713 }
714 }
715
716 if (page > pool->pages) {
717 join = page - 1;
718 type = join->prev & NGX_SLAB_PAGE_MASK;
719
720 if (type == NGX_SLAB_PAGE) {
721
722 if (join->slab == NGX_SLAB_PAGE_FREE) {
723 join = (ngx_slab_page_t *) (join->prev & ~NGX_SLAB_PAGE_MASK);
724 }
725
726 if (join->next != NULL) {
727 pages += join->slab;
728 join->slab += page->slab;
729
730 prev = (ngx_slab_page_t *) (join->prev & ~NGX_SLAB_PAGE_MASK);
731 prev->next = join->next;
732 join->next->prev = join->prev;
733
734 page->slab = NGX_SLAB_PAGE_FREE;
735 page->next = NULL;
736 page->prev = NGX_SLAB_PAGE;
737
738 page = join;
739 }
740 }
741 }
742
743 if (pages) {
744 page[pages].prev = (uintptr_t) page;
687 } 745 }
688 746
689 page->prev = (uintptr_t) &pool->free; 747 page->prev = (uintptr_t) &pool->free;
690 page->next = pool->free.next; 748 page->next = pool->free.next;
691 749