Commit b12f642c authored by Benoit Lize's avatar Benoit Lize Committed by Chromium LUCI CQ

[PartitionAlloc] Better diagnostics for out-of-address space OOM crashes.

PartitionAlloc may use more virtual address space than other allocators,
since the normal bucket superpages are never released to the operating
system, by design.

This is likely causing some issues on Windows 32 bit, where the virtual
address space is typically only 2GiB per process.

Bug: 998048
Change-Id: I77f1e142b5092121db7ab30aafb74e8daca72088
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2584027Reviewed-by: default avatarChris Palmer <palmer@chromium.org>
Commit-Queue: Benoit L <lizeb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#838013}
parent 1958c68a
......@@ -16,7 +16,7 @@
namespace {
// The crash is generated in a NOINLINE function so that we can classify the
// crash as an OOM solely by analyzing the stack trace.
NOINLINE void OnNoMemory(size_t size) {
[[noreturn]] NOINLINE void OnNoMemory(size_t size) {
base::internal::RunPartitionAllocOomCallback();
base::internal::OnNoMemoryInternal(size);
IMMEDIATE_CRASH();
......
......@@ -20,7 +20,13 @@ void NOINLINE PartitionExcessiveAllocationSize(size_t size) {
NOINLINE void PartitionOutOfMemoryWithLotsOfUncommitedPages(size_t size) {
OOM_CRASH(size);
}
#endif
[[noreturn]] NOINLINE void PartitionOutOfMemoryWithLargeVirtualSize(
size_t virtual_size) {
OOM_CRASH(virtual_size);
}
#endif // !defined(ARCH_CPU_64_BITS)
} // namespace internal
} // namespace base
......@@ -23,10 +23,14 @@ namespace internal {
// g_oom_handling_function is invoked when PartitionAlloc hits OutOfMemory.
extern OomFunction g_oom_handling_function;
BASE_EXPORT NOINLINE void PartitionExcessiveAllocationSize(size_t size);
[[noreturn]] BASE_EXPORT NOINLINE void PartitionExcessiveAllocationSize(
size_t size);
#if !defined(ARCH_CPU_64_BITS)
NOINLINE void PartitionOutOfMemoryWithLotsOfUncommitedPages(size_t size);
[[noreturn]] NOINLINE void PartitionOutOfMemoryWithLotsOfUncommitedPages(
size_t size);
[[noreturn]] NOINLINE void PartitionOutOfMemoryWithLargeVirtualSize(
size_t virtual_size);
#endif
} // namespace internal
......
......@@ -310,17 +310,38 @@ void DCheckIfManagedByPartitionAllocNormalBuckets(const void* ptr) {
} // namespace internal
template <bool thread_safe>
NOINLINE void PartitionRoot<thread_safe>::OutOfMemory(size_t size) {
[[noreturn]] NOINLINE void PartitionRoot<thread_safe>::OutOfMemory(
size_t size) {
#if !defined(ARCH_CPU_64_BITS)
size_t virtual_address_space_size =
total_size_of_super_pages.load(std::memory_order_relaxed) +
total_size_of_direct_mapped_pages.load(std::memory_order_relaxed);
size_t uncommitted_size =
virtual_address_space_size -
total_size_of_committed_pages.load(std::memory_order_relaxed);
// 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 (total_size_of_super_pages.load(std::memory_order_relaxed) +
total_size_of_direct_mapped_pages.load(std::memory_order_relaxed) -
total_size_of_committed_pages.load(std::memory_order_relaxed) >
kReasonableSizeOfUnusedPages) {
if (uncommitted_size > kReasonableSizeOfUnusedPages) {
internal::PartitionOutOfMemoryWithLotsOfUncommitedPages(size);
}
constexpr size_t kReasonableVirtualSize =
#if defined(OS_WIN)
// 1GiB on Windows, as the entire address space is typically 2GiB.
1024 * 1024 * 1024;
#else
// 1.5GiB elsewhere, since address space is typically 3GiB.
(1024 + 512) * 1024 * 1024;
#endif
if (virtual_address_space_size > kReasonableVirtualSize) {
internal::PartitionOutOfMemoryWithLargeVirtualSize(
virtual_address_space_size);
}
// Make the virtual size visible to crash reports all the time.
base::debug::Alias(&virtual_address_space_size);
#endif
if (internal::g_oom_handling_function)
(*internal::g_oom_handling_function)(size);
......
......@@ -246,7 +246,7 @@ struct BASE_EXPORT PartitionRoot {
PageAccessibilityDisposition accessibility_disposition)
EXCLUSIVE_LOCKS_REQUIRED(lock_);
NOINLINE void OutOfMemory(size_t size);
[[noreturn]] NOINLINE void OutOfMemory(size_t size);
// Returns a pointer aligned on |alignment|, or nullptr.
//
......
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