Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(473)

Unified Diff: Source/wtf/PartitionAlloc.cpp

Issue 26196002: Improve partitionAlloc's resistance to fragmentation. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | Source/wtf/PartitionAllocTest.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/wtf/PartitionAlloc.cpp
diff --git a/Source/wtf/PartitionAlloc.cpp b/Source/wtf/PartitionAlloc.cpp
index e1376d31d15f73e398eda6597064477621cbaf70..cb5dc0a85a4f984a9e5ae3df27e4fd4afe4dcf53 100644
--- a/Source/wtf/PartitionAlloc.cpp
+++ b/Source/wtf/PartitionAlloc.cpp
@@ -31,7 +31,6 @@
#include "config.h"
#include "wtf/PartitionAlloc.h"
-#include "wtf/PageAllocator.h"
#include <string.h>
#ifndef NDEBUG
@@ -285,16 +284,16 @@ static ALWAYS_INLINE void partitionUnlinkPage(PartitionPageHeader* page)
page->prev->next = page->next;
}
-static ALWAYS_INLINE void partitionLinkPage(PartitionPageHeader* newPage, PartitionPageHeader* prevPage)
+static ALWAYS_INLINE void partitionLinkPageBefore(PartitionPageHeader* newPage, PartitionPageHeader* nextPage)
{
- ASSERT(prevPage->prev->next == prevPage);
- ASSERT(prevPage->next->prev == prevPage);
+ ASSERT(nextPage->prev->next == nextPage);
+ ASSERT(nextPage->next->prev == nextPage);
- newPage->prev = prevPage;
- newPage->next = prevPage->next;
+ newPage->next = nextPage;
+ newPage->prev = nextPage->prev;
- prevPage->next->prev = newPage;
- prevPage->next = newPage;
+ nextPage->prev->next = newPage;
+ nextPage->prev = newPage;
}
void* partitionAllocSlowPath(PartitionBucket* bucket)
@@ -304,8 +303,8 @@ void* partitionAllocSlowPath(PartitionBucket* bucket)
PartitionPageHeader* next = page->next;
ASSERT(page == &bucket->root->seedPage || (page->bucket == bucket && next->bucket == bucket));
- // First, see if the partition page still has capacity and if so, fill out
- // the freelist a little more.
+ // First, see if the current partition page still has capacity and if so,
+ // fill out the freelist a little more.
if (LIKELY(page->numUnprovisionedSlots))
return partitionPageAllocAndFillFreelist(page);
@@ -322,6 +321,10 @@ void* partitionAllocSlowPath(PartitionBucket* bucket)
next->numAllocatedSlots++;
return ret;
}
+ if (LIKELY(next->numUnprovisionedSlots)) {
+ bucket->currPage = next;
+ return partitionPageAllocAndFillFreelist(next);
+ }
// Pull this page out of the non-full page list, since it has no free
// slots.
// This tags the page as full so that free'ing can tell, and move
@@ -334,7 +337,18 @@ void* partitionAllocSlowPath(PartitionBucket* bucket)
next = next->next;
}
- // Second, look in our list of freed but reserved pages.
+ // After we've considered and rejected every partition page in the list,
+ // we should by definition have a single self-linked page left. We will
+ // replace this single page with the new page we choose.
+ ASSERT(page == page->next);
+ ASSERT(page == page->prev);
+ ASSERT(page == &bucket->root->seedPage || page->numAllocatedSlots == partitionBucketSlots(bucket));
+ if (LIKELY(page != &bucket->root->seedPage)) {
+ page->numAllocatedSlots = -page->numAllocatedSlots;
+ ++bucket->numFullPages;
+ }
+
+ // Third, look in our list of freed but reserved pages.
PartitionPageHeader* newPage;
PartitionFreepagelistEntry* pagelist = bucket->freePages;
if (LIKELY(pagelist != 0)) {
@@ -342,21 +356,13 @@ void* partitionAllocSlowPath(PartitionBucket* bucket)
bucket->freePages = pagelist->next;
partitionFree(pagelist);
ASSERT(page != &bucket->root->seedPage);
- partitionLinkPage(newPage, page);
} else {
- // Third. If we get here, we need a brand new page.
+ // Fourth. If we get here, we need a brand new page.
newPage = partitionAllocPage(bucket->root);
- if (UNLIKELY(page == &bucket->root->seedPage)) {
- // If this is the first page allocation to this bucket, then
- // fully replace the seed page. This avoids pointlessly iterating
- // over it.
- newPage->prev = newPage;
- newPage->next = newPage;
- } else {
- partitionLinkPage(newPage, page);
- }
}
+ newPage->prev = newPage;
+ newPage->next = newPage;
bucket->currPage = newPage;
partitionPageReset(newPage, bucket);
return partitionPageAllocAndFillFreelist(newPage);
@@ -367,10 +373,14 @@ void partitionFreeSlowPath(PartitionPageHeader* page)
PartitionBucket* bucket = page->bucket;
if (LIKELY(page->numAllocatedSlots == 0)) {
// Page became fully unused.
- // If it's the current page, leave it be so that we don't bounce a page
- // onto the free page list and immediately back out again.
- if (LIKELY(page == bucket->currPage))
- return;
+ // If it's the current page, change it!
+ if (LIKELY(page == bucket->currPage)) {
+ if (UNLIKELY(page->next == page)) {
+ // For now, we do not free the last partition page in a bucket.
+ return;
+ }
+ bucket->currPage = page->next;
+ }
partitionUnlinkPage(page);
partitionUnusePage(page);
@@ -380,8 +390,11 @@ void partitionFreeSlowPath(PartitionPageHeader* page)
bucket->freePages = entry;
} else {
// Fully used page became partially used. It must be put back on the
- // non-full page list.
- partitionLinkPage(page, bucket->currPage);
+ // non-full page list. Also make it the current page to increase the
+ // chances of it being filled up again. The old current page will be
+ // the next page.
+ partitionLinkPageBefore(page, bucket->currPage);
+ bucket->currPage = page;
page->numAllocatedSlots = -page->numAllocatedSlots - 2;
ASSERT(page->numAllocatedSlots == partitionBucketSlots(bucket) - 1);
--bucket->numFullPages;
« no previous file with comments | « no previous file | Source/wtf/PartitionAllocTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698