mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
251 lines
8.9 KiB
C++
251 lines
8.9 KiB
C++
/*
|
|
* Copyright (C) 2013 Google Inc. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above
|
|
* copyright notice, this list of conditions and the following disclaimer
|
|
* in the documentation and/or other materials provided with the
|
|
* distribution.
|
|
* * Neither the name of Google Inc. nor the names of its
|
|
* contributors may be used to endorse or promote products derived from
|
|
* this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "platform/wtf/allocator/Partitions.h"
|
|
|
|
#include "base/allocator/partition_allocator/oom.h"
|
|
#include "base/allocator/partition_allocator/page_allocator.h"
|
|
#include "base/debug/alias.h"
|
|
#include "base/lazy_instance.h"
|
|
#include "platform/wtf/allocator/PartitionAllocator.h"
|
|
|
|
namespace WTF {
|
|
|
|
const char* const Partitions::kAllocatedObjectPoolName =
|
|
"partition_alloc/allocated_objects";
|
|
|
|
static base::LazyInstance<base::subtle::SpinLock>::Leaky initialization_lock_ =
|
|
LAZY_INSTANCE_INITIALIZER;
|
|
bool Partitions::initialized_ = false;
|
|
|
|
// These statics are inlined, so cannot be LazyInstances. We create
|
|
// LazyInstances below, and then set the pointers correctly in Initialize().
|
|
base::PartitionAllocatorGeneric* Partitions::fast_malloc_allocator_ = nullptr;
|
|
base::PartitionAllocatorGeneric* Partitions::array_buffer_allocator_ = nullptr;
|
|
base::PartitionAllocatorGeneric* Partitions::buffer_allocator_ = nullptr;
|
|
base::SizeSpecificPartitionAllocator<1024>* Partitions::layout_allocator_ =
|
|
nullptr;
|
|
|
|
static base::LazyInstance<base::PartitionAllocatorGeneric>::Leaky
|
|
lazy_fast_malloc = LAZY_INSTANCE_INITIALIZER;
|
|
static base::LazyInstance<base::PartitionAllocatorGeneric>::Leaky
|
|
lazy_array_buffer = LAZY_INSTANCE_INITIALIZER;
|
|
static base::LazyInstance<base::PartitionAllocatorGeneric>::Leaky lazy_buffer =
|
|
LAZY_INSTANCE_INITIALIZER;
|
|
static base::LazyInstance<base::SizeSpecificPartitionAllocator<1024>>::Leaky
|
|
lazy_layout = LAZY_INSTANCE_INITIALIZER;
|
|
|
|
Partitions::ReportPartitionAllocSizeFunction Partitions::report_size_function_ =
|
|
nullptr;
|
|
|
|
void Partitions::Initialize(
|
|
ReportPartitionAllocSizeFunction report_size_function) {
|
|
base::subtle::SpinLock::Guard guard(initialization_lock_.Get());
|
|
|
|
if (!initialized_) {
|
|
fast_malloc_allocator_ = lazy_fast_malloc.Pointer();
|
|
array_buffer_allocator_ = lazy_array_buffer.Pointer();
|
|
buffer_allocator_ = lazy_buffer.Pointer();
|
|
layout_allocator_ = lazy_layout.Pointer();
|
|
|
|
base::PartitionAllocGlobalInit(&Partitions::HandleOutOfMemory);
|
|
fast_malloc_allocator_->init();
|
|
array_buffer_allocator_->init();
|
|
buffer_allocator_->init();
|
|
layout_allocator_->init();
|
|
report_size_function_ = report_size_function;
|
|
initialized_ = true;
|
|
}
|
|
}
|
|
|
|
void Partitions::DecommitFreeableMemory() {
|
|
CHECK(IsMainThread());
|
|
if (!initialized_)
|
|
return;
|
|
|
|
base::PartitionPurgeMemoryGeneric(
|
|
ArrayBufferPartition(), base::PartitionPurgeDecommitEmptyPages |
|
|
base::PartitionPurgeDiscardUnusedSystemPages);
|
|
base::PartitionPurgeMemoryGeneric(
|
|
BufferPartition(), base::PartitionPurgeDecommitEmptyPages |
|
|
base::PartitionPurgeDiscardUnusedSystemPages);
|
|
base::PartitionPurgeMemoryGeneric(
|
|
FastMallocPartition(), base::PartitionPurgeDecommitEmptyPages |
|
|
base::PartitionPurgeDiscardUnusedSystemPages);
|
|
base::PartitionPurgeMemory(LayoutPartition(),
|
|
base::PartitionPurgeDecommitEmptyPages |
|
|
base::PartitionPurgeDiscardUnusedSystemPages);
|
|
}
|
|
|
|
void Partitions::ReportMemoryUsageHistogram() {
|
|
static size_t observed_max_size_in_mb = 0;
|
|
|
|
if (!report_size_function_)
|
|
return;
|
|
// We only report the memory in the main thread.
|
|
if (!IsMainThread())
|
|
return;
|
|
// +1 is for rounding up the sizeInMB.
|
|
size_t size_in_mb = Partitions::TotalSizeOfCommittedPages() / 1024 / 1024 + 1;
|
|
if (size_in_mb > observed_max_size_in_mb) {
|
|
report_size_function_(size_in_mb);
|
|
observed_max_size_in_mb = size_in_mb;
|
|
}
|
|
}
|
|
|
|
void Partitions::DumpMemoryStats(
|
|
bool is_light_dump,
|
|
base::PartitionStatsDumper* partition_stats_dumper) {
|
|
// Object model and rendering partitions are not thread safe and can be
|
|
// accessed only on the main thread.
|
|
DCHECK(IsMainThread());
|
|
|
|
DecommitFreeableMemory();
|
|
PartitionDumpStatsGeneric(FastMallocPartition(), "fast_malloc", is_light_dump,
|
|
partition_stats_dumper);
|
|
PartitionDumpStatsGeneric(ArrayBufferPartition(), "array_buffer",
|
|
is_light_dump, partition_stats_dumper);
|
|
PartitionDumpStatsGeneric(BufferPartition(), "buffer", is_light_dump,
|
|
partition_stats_dumper);
|
|
PartitionDumpStats(LayoutPartition(), "layout", is_light_dump,
|
|
partition_stats_dumper);
|
|
}
|
|
|
|
namespace {
|
|
|
|
class LightPartitionStatsDumperImpl : public WTF::PartitionStatsDumper {
|
|
public:
|
|
LightPartitionStatsDumperImpl() : total_active_bytes_(0) {}
|
|
|
|
void PartitionDumpTotals(
|
|
const char* partition_name,
|
|
const WTF::PartitionMemoryStats* memory_stats) override {
|
|
total_active_bytes_ += memory_stats->total_active_bytes;
|
|
}
|
|
|
|
void PartitionsDumpBucketStats(
|
|
const char* partition_name,
|
|
const WTF::PartitionBucketMemoryStats*) override {}
|
|
|
|
size_t TotalActiveBytes() const { return total_active_bytes_; }
|
|
|
|
private:
|
|
size_t total_active_bytes_;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
size_t Partitions::TotalActiveBytes() {
|
|
LightPartitionStatsDumperImpl dumper;
|
|
WTF::Partitions::DumpMemoryStats(true, &dumper);
|
|
return dumper.TotalActiveBytes();
|
|
}
|
|
|
|
static NEVER_INLINE void PartitionsOutOfMemoryUsing2G() {
|
|
size_t signature = 2UL * 1024 * 1024 * 1024;
|
|
base::debug::Alias(&signature);
|
|
OOM_CRASH();
|
|
}
|
|
|
|
static NEVER_INLINE void PartitionsOutOfMemoryUsing1G() {
|
|
size_t signature = 1UL * 1024 * 1024 * 1024;
|
|
base::debug::Alias(&signature);
|
|
OOM_CRASH();
|
|
}
|
|
|
|
static NEVER_INLINE void PartitionsOutOfMemoryUsing512M() {
|
|
size_t signature = 512 * 1024 * 1024;
|
|
base::debug::Alias(&signature);
|
|
OOM_CRASH();
|
|
}
|
|
|
|
static NEVER_INLINE void PartitionsOutOfMemoryUsing256M() {
|
|
size_t signature = 256 * 1024 * 1024;
|
|
base::debug::Alias(&signature);
|
|
OOM_CRASH();
|
|
}
|
|
|
|
static NEVER_INLINE void PartitionsOutOfMemoryUsing128M() {
|
|
size_t signature = 128 * 1024 * 1024;
|
|
base::debug::Alias(&signature);
|
|
OOM_CRASH();
|
|
}
|
|
|
|
static NEVER_INLINE void PartitionsOutOfMemoryUsing64M() {
|
|
size_t signature = 64 * 1024 * 1024;
|
|
base::debug::Alias(&signature);
|
|
OOM_CRASH();
|
|
}
|
|
|
|
static NEVER_INLINE void PartitionsOutOfMemoryUsing32M() {
|
|
size_t signature = 32 * 1024 * 1024;
|
|
base::debug::Alias(&signature);
|
|
OOM_CRASH();
|
|
}
|
|
|
|
static NEVER_INLINE void PartitionsOutOfMemoryUsing16M() {
|
|
size_t signature = 16 * 1024 * 1024;
|
|
base::debug::Alias(&signature);
|
|
OOM_CRASH();
|
|
}
|
|
|
|
static NEVER_INLINE void PartitionsOutOfMemoryUsingLessThan16M() {
|
|
size_t signature = 16 * 1024 * 1024 - 1;
|
|
base::debug::Alias(&signature);
|
|
DLOG(FATAL) << "ParitionAlloc: out of memory with < 16M usage (error:"
|
|
<< GetAllocPageErrorCode() << ")";
|
|
}
|
|
|
|
void Partitions::HandleOutOfMemory() {
|
|
volatile size_t total_usage = TotalSizeOfCommittedPages();
|
|
uint32_t alloc_page_error_code = GetAllocPageErrorCode();
|
|
base::debug::Alias(&alloc_page_error_code);
|
|
|
|
if (total_usage >= 2UL * 1024 * 1024 * 1024)
|
|
PartitionsOutOfMemoryUsing2G();
|
|
if (total_usage >= 1UL * 1024 * 1024 * 1024)
|
|
PartitionsOutOfMemoryUsing1G();
|
|
if (total_usage >= 512 * 1024 * 1024)
|
|
PartitionsOutOfMemoryUsing512M();
|
|
if (total_usage >= 256 * 1024 * 1024)
|
|
PartitionsOutOfMemoryUsing256M();
|
|
if (total_usage >= 128 * 1024 * 1024)
|
|
PartitionsOutOfMemoryUsing128M();
|
|
if (total_usage >= 64 * 1024 * 1024)
|
|
PartitionsOutOfMemoryUsing64M();
|
|
if (total_usage >= 32 * 1024 * 1024)
|
|
PartitionsOutOfMemoryUsing32M();
|
|
if (total_usage >= 16 * 1024 * 1024)
|
|
PartitionsOutOfMemoryUsing16M();
|
|
PartitionsOutOfMemoryUsingLessThan16M();
|
|
}
|
|
|
|
} // namespace WTF
|