diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 65df15b4005a..3b2473463b54 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2011-10-18 Andi Kleen + + * ggc-page (release_pages): First free large continuous + chunks in the madvise path. + 2011-10-18 Andi Kleen * ggc-page.c (alloc_pages): Always round up entry_size. diff --git a/gcc/ggc-page.c b/gcc/ggc-page.c index 077bc8e2beef..7bef4c02d348 100644 --- a/gcc/ggc-page.c +++ b/gcc/ggc-page.c @@ -973,6 +973,54 @@ release_pages (void) page_entry *p, *start_p; char *start; size_t len; + size_t mapped_len; + page_entry *next, *prev, *newprev; + size_t free_unit = (GGC_QUIRE_SIZE/2) * G.pagesize; + + /* First free larger continuous areas to the OS. + This allows other allocators to grab these areas if needed. + This is only done on larger chunks to avoid fragmentation. + This does not always work because the free_pages list is only + approximately sorted. */ + + p = G.free_pages; + prev = NULL; + while (p) + { + start = p->page; + start_p = p; + len = 0; + mapped_len = 0; + newprev = prev; + while (p && p->page == start + len) + { + len += p->bytes; + if (!p->discarded) + mapped_len += p->bytes; + newprev = p; + p = p->next; + } + if (len >= free_unit) + { + while (start_p != p) + { + next = start_p->next; + free (start_p); + start_p = next; + } + munmap (start, len); + if (prev) + prev->next = p; + else + G.free_pages = p; + G.bytes_mapped -= mapped_len; + continue; + } + prev = newprev; + } + + /* Now give back the fragmented pages to the OS, but keep the address + space to reuse it next time. */ for (p = G.free_pages; p; ) {