PartitionAlloc: Distinguish OOMs where a lot of super pages are not committed.

This CL distinguishes
specific OOMs (where a lot of super pages are allocated but not committed) from
actual OOMs (where a lot of physical memory is allocated) in crash reports.
- By crashing in partitionOutOfMemoryWithLotsOfUncommitedPages.
- By crashing at a special address (0x9b) in Windows, because reported stack
  traces are not accurate.
This check is enabled on 32-bit environments only.

BUG=421387

Review URL: https://codereview.chromium.org/683043002

git-svn-id: svn://svn.chromium.org/blink/trunk@185286 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent e2deb142
...@@ -114,6 +114,7 @@ static void parititonAllocBaseInit(PartitionRootBase* root) ...@@ -114,6 +114,7 @@ static void parititonAllocBaseInit(PartitionRootBase* root)
root->initialized = true; root->initialized = true;
root->totalSizeOfCommittedPages = 0; root->totalSizeOfCommittedPages = 0;
root->totalSizeOfSuperPages = 0; root->totalSizeOfSuperPages = 0;
root->totalSizeOfDirectMappedPages = 0;
root->nextSuperPage = 0; root->nextSuperPage = 0;
root->nextPartitionPage = 0; root->nextPartitionPage = 0;
root->nextPartitionPageEnd = 0; root->nextPartitionPageEnd = 0;
...@@ -296,15 +297,41 @@ bool partitionAllocGenericShutdown(PartitionRootGeneric* root) ...@@ -296,15 +297,41 @@ bool partitionAllocGenericShutdown(PartitionRootGeneric* root)
return noLeaks; return noLeaks;
} }
static NEVER_INLINE void partitionOutOfMemory() #if !CPU(64BIT)
static NEVER_INLINE void partitionOutOfMemoryWithLotsOfUncommitedPages()
{ {
#if OS(WIN)
// Crash at a special address (0x9b)
// to be easily distinguished on crash reports.
// This is because crash stack traces are inaccurate on Windows and
// partitionOutOfMemoryWithLotsOfUncommitedPages might be not included
// in the stack traces.
reinterpret_cast<void(*)()>(0x9b)();
#endif
// On non-Windows environment, IMMEDIATE_CRASH is sufficient
// because partitionOutOfMemoryWithLotsOfUncommitedPages will appear
// in crash stack traces.
IMMEDIATE_CRASH();
}
#endif
static NEVER_INLINE void partitionOutOfMemory(const PartitionRootBase* root)
{
#if !CPU(64BIT)
// Check whether this OOM is due to a lot of super pages that are allocated
// but not committed, probably due to http://crbug.com/421387.
if (root->totalSizeOfSuperPages + root->totalSizeOfDirectMappedPages - root->totalSizeOfCommittedPages > kReasonableSizeOfUnusedPages) {
partitionOutOfMemoryWithLotsOfUncommitedPages();
}
#endif
IMMEDIATE_CRASH(); IMMEDIATE_CRASH();
} }
static ALWAYS_INLINE void partitionDecommitSystemPages(PartitionRootBase* root, void* addr, size_t len) static ALWAYS_INLINE void partitionDecommitSystemPages(PartitionRootBase* root, void* addr, size_t len)
{ {
decommitSystemPages(addr, len); decommitSystemPages(addr, len);
ASSERT(root->totalSizeOfCommittedPages > len); ASSERT(root->totalSizeOfCommittedPages >= len);
root->totalSizeOfCommittedPages -= len; root->totalSizeOfCommittedPages -= len;
} }
...@@ -312,6 +339,7 @@ static ALWAYS_INLINE void partitionRecommitSystemPages(PartitionRootBase* root, ...@@ -312,6 +339,7 @@ static ALWAYS_INLINE void partitionRecommitSystemPages(PartitionRootBase* root,
{ {
recommitSystemPages(addr, len); recommitSystemPages(addr, len);
root->totalSizeOfCommittedPages += len; root->totalSizeOfCommittedPages += len;
ASSERT(root->totalSizeOfCommittedPages <= root->totalSizeOfSuperPages + root->totalSizeOfDirectMappedPages);
} }
static ALWAYS_INLINE void* partitionAllocPartitionPages(PartitionRootBase* root, int flags, uint16_t numPartitionPages) static ALWAYS_INLINE void* partitionAllocPartitionPages(PartitionRootBase* root, int flags, uint16_t numPartitionPages)
...@@ -327,6 +355,7 @@ static ALWAYS_INLINE void* partitionAllocPartitionPages(PartitionRootBase* root, ...@@ -327,6 +355,7 @@ static ALWAYS_INLINE void* partitionAllocPartitionPages(PartitionRootBase* root,
char* ret = root->nextPartitionPage; char* ret = root->nextPartitionPage;
root->nextPartitionPage += totalSize; root->nextPartitionPage += totalSize;
root->totalSizeOfCommittedPages += totalSize; root->totalSizeOfCommittedPages += totalSize;
ASSERT(root->totalSizeOfCommittedPages <= root->totalSizeOfSuperPages + root->totalSizeOfDirectMappedPages);
return ret; return ret;
} }
...@@ -338,6 +367,7 @@ static ALWAYS_INLINE void* partitionAllocPartitionPages(PartitionRootBase* root, ...@@ -338,6 +367,7 @@ static ALWAYS_INLINE void* partitionAllocPartitionPages(PartitionRootBase* root,
root->totalSizeOfSuperPages += kSuperPageSize; root->totalSizeOfSuperPages += kSuperPageSize;
root->totalSizeOfCommittedPages += totalSize; root->totalSizeOfCommittedPages += totalSize;
ASSERT(root->totalSizeOfCommittedPages <= root->totalSizeOfSuperPages + root->totalSizeOfDirectMappedPages);
root->nextSuperPage = superPage + kSuperPageSize; root->nextSuperPage = superPage + kSuperPageSize;
char* ret = superPage + kPartitionPageSize; char* ret = superPage + kPartitionPageSize;
...@@ -568,7 +598,10 @@ static ALWAYS_INLINE void* partitionDirectMap(PartitionRootBase* root, int flags ...@@ -568,7 +598,10 @@ static ALWAYS_INLINE void* partitionDirectMap(PartitionRootBase* root, int flags
mapSize += kPageAllocationGranularityOffsetMask; mapSize += kPageAllocationGranularityOffsetMask;
mapSize &= kPageAllocationGranularityBaseMask; mapSize &= kPageAllocationGranularityBaseMask;
root->totalSizeOfCommittedPages += size + kSystemPageSize; size_t committedPageSize = size + kSystemPageSize;
root->totalSizeOfCommittedPages += committedPageSize;
root->totalSizeOfDirectMappedPages += committedPageSize;
ASSERT(root->totalSizeOfCommittedPages <= root->totalSizeOfSuperPages + root->totalSizeOfDirectMappedPages);
// TODO: we may want to let the operating system place these allocations // TODO: we may want to let the operating system place these allocations
// where it pleases. On 32-bit, this might limit address space // where it pleases. On 32-bit, this might limit address space
...@@ -624,7 +657,11 @@ static ALWAYS_INLINE void partitionDirectUnmap(PartitionPage* page) ...@@ -624,7 +657,11 @@ static ALWAYS_INLINE void partitionDirectUnmap(PartitionPage* page)
unmapSize += kPartitionPageSize + kSystemPageSize; unmapSize += kPartitionPageSize + kSystemPageSize;
PartitionRootBase* root = partitionPageToRoot(page); PartitionRootBase* root = partitionPageToRoot(page);
root->totalSizeOfCommittedPages -= page->bucket->slotSize + kSystemPageSize; size_t uncommittedPageSize = page->bucket->slotSize + kSystemPageSize;
ASSERT(root->totalSizeOfCommittedPages >= uncommittedPageSize);
root->totalSizeOfCommittedPages -= uncommittedPageSize;
ASSERT(root->totalSizeOfDirectMappedPages >= uncommittedPageSize);
root->totalSizeOfDirectMappedPages -= uncommittedPageSize;
ASSERT(!(unmapSize & kPageAllocationGranularityOffsetMask)); ASSERT(!(unmapSize & kPageAllocationGranularityOffsetMask));
...@@ -709,7 +746,7 @@ partitionAllocSlowPathFailed: ...@@ -709,7 +746,7 @@ partitionAllocSlowPathFailed:
bucket->activePagesHead = &PartitionRootGeneric::gSeedPage; bucket->activePagesHead = &PartitionRootGeneric::gSeedPage;
return nullptr; return nullptr;
} }
partitionOutOfMemory(); partitionOutOfMemory(root);
return nullptr; return nullptr;
} }
......
...@@ -184,6 +184,13 @@ static const size_t kBitsPerSizet = sizeof(void*) * CHAR_BIT; ...@@ -184,6 +184,13 @@ static const size_t kBitsPerSizet = sizeof(void*) * CHAR_BIT;
// Constants for the memory reclaim logic. // Constants for the memory reclaim logic.
static const size_t kMaxFreeableSpans = 16; static const size_t kMaxFreeableSpans = 16;
// If the total size in bytes of allocated but not committed pages exceeds this
// value (probably it is a "out of virtual address space" crash),
// a special crash stack trace is generated at |partitionOutOfMemory|.
// This is to distinguish "out of virtual address space" from
// "out of physical memory" in crash reports.
static const size_t kReasonableSizeOfUnusedPages = 1024 * 1024 * 1024; // 1GiB
#if ENABLE(ASSERT) #if ENABLE(ASSERT)
// These two byte values match tcmalloc. // These two byte values match tcmalloc.
static const unsigned char kUninitializedByte = 0xAB; static const unsigned char kUninitializedByte = 0xAB;
...@@ -250,6 +257,8 @@ struct PartitionSuperPageExtentEntry { ...@@ -250,6 +257,8 @@ struct PartitionSuperPageExtentEntry {
struct WTF_EXPORT PartitionRootBase { struct WTF_EXPORT PartitionRootBase {
size_t totalSizeOfCommittedPages; size_t totalSizeOfCommittedPages;
size_t totalSizeOfSuperPages; size_t totalSizeOfSuperPages;
size_t totalSizeOfDirectMappedPages;
// Invariant: totalSizeOfCommittedPages <= totalSizeOfSuperPages + totalSizeOfDirectMappedPages.
unsigned numBuckets; unsigned numBuckets;
unsigned maxAllocation; unsigned maxAllocation;
bool initialized; bool initialized;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment