| Index: content/common/host_discardable_shared_memory_manager.cc
|
| diff --git a/content/common/host_discardable_shared_memory_manager.cc b/content/common/host_discardable_shared_memory_manager.cc
|
| deleted file mode 100644
|
| index e349fca4171c1a32a1daf1ef22f50913e1d7c89f..0000000000000000000000000000000000000000
|
| --- a/content/common/host_discardable_shared_memory_manager.cc
|
| +++ /dev/null
|
| @@ -1,580 +0,0 @@
|
| -// Copyright 2014 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "content/common/host_discardable_shared_memory_manager.h"
|
| -
|
| -#include <algorithm>
|
| -#include <utility>
|
| -
|
| -#include "base/atomic_sequence_num.h"
|
| -#include "base/bind.h"
|
| -#include "base/callback.h"
|
| -#include "base/debug/crash_logging.h"
|
| -#include "base/lazy_instance.h"
|
| -#include "base/macros.h"
|
| -#include "base/memory/discardable_memory.h"
|
| -#include "base/memory/memory_coordinator_client_registry.h"
|
| -#include "base/memory/ptr_util.h"
|
| -#include "base/numerics/safe_math.h"
|
| -#include "base/process/memory.h"
|
| -#include "base/strings/string_number_conversions.h"
|
| -#include "base/strings/stringprintf.h"
|
| -#include "base/sys_info.h"
|
| -#include "base/threading/thread_task_runner_handle.h"
|
| -#include "base/trace_event/memory_allocator_dump.h"
|
| -#include "base/trace_event/memory_dump_manager.h"
|
| -#include "base/trace_event/process_memory_dump.h"
|
| -#include "base/trace_event/trace_event.h"
|
| -#include "build/build_config.h"
|
| -#include "content/common/child_process_host_impl.h"
|
| -#include "content/common/discardable_shared_memory_heap.h"
|
| -#include "content/public/common/child_process_host.h"
|
| -
|
| -#if defined(OS_LINUX)
|
| -#include "base/files/file_path.h"
|
| -#include "base/files/file_util.h"
|
| -#include "base/metrics/histogram_macros.h"
|
| -#endif
|
| -
|
| -namespace content {
|
| -namespace {
|
| -
|
| -class DiscardableMemoryImpl : public base::DiscardableMemory {
|
| - public:
|
| - DiscardableMemoryImpl(
|
| - std::unique_ptr<base::DiscardableSharedMemory> shared_memory,
|
| - const base::Closure& deleted_callback)
|
| - : shared_memory_(std::move(shared_memory)),
|
| - deleted_callback_(deleted_callback),
|
| - is_locked_(true) {}
|
| -
|
| - ~DiscardableMemoryImpl() override {
|
| - if (is_locked_)
|
| - shared_memory_->Unlock(0, 0);
|
| -
|
| - deleted_callback_.Run();
|
| - }
|
| -
|
| - // Overridden from base::DiscardableMemory:
|
| - bool Lock() override {
|
| - DCHECK(!is_locked_);
|
| -
|
| - if (shared_memory_->Lock(0, 0) != base::DiscardableSharedMemory::SUCCESS)
|
| - return false;
|
| -
|
| - is_locked_ = true;
|
| - return true;
|
| - }
|
| - void Unlock() override {
|
| - DCHECK(is_locked_);
|
| -
|
| - shared_memory_->Unlock(0, 0);
|
| - is_locked_ = false;
|
| - }
|
| - void* data() const override {
|
| - DCHECK(is_locked_);
|
| - return shared_memory_->memory();
|
| - }
|
| -
|
| - base::trace_event::MemoryAllocatorDump* CreateMemoryAllocatorDump(
|
| - const char* name,
|
| - base::trace_event::ProcessMemoryDump* pmd) const override {
|
| - // The memory could have been purged, but we still create a dump with
|
| - // mapped_size. So, the size can be inaccurate.
|
| - base::trace_event::MemoryAllocatorDump* dump =
|
| - pmd->CreateAllocatorDump(name);
|
| - dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
|
| - base::trace_event::MemoryAllocatorDump::kUnitsBytes,
|
| - shared_memory_->mapped_size());
|
| - return dump;
|
| - }
|
| -
|
| - private:
|
| - std::unique_ptr<base::DiscardableSharedMemory> shared_memory_;
|
| - const base::Closure deleted_callback_;
|
| - bool is_locked_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(DiscardableMemoryImpl);
|
| -};
|
| -
|
| -// Returns the default memory limit to use for discardable memory, taking
|
| -// the amount physical memory available and other platform specific constraints
|
| -// into account.
|
| -int64_t GetDefaultMemoryLimit() {
|
| - const int kMegabyte = 1024 * 1024;
|
| -
|
| -#if defined(OS_ANDROID)
|
| - // Limits the number of FDs used to 32, assuming a 4MB allocation size.
|
| - int64_t max_default_memory_limit = 128 * kMegabyte;
|
| -#else
|
| - int64_t max_default_memory_limit = 512 * kMegabyte;
|
| -#endif
|
| -
|
| - // Use 1/8th of discardable memory on low-end devices.
|
| - if (base::SysInfo::IsLowEndDevice())
|
| - max_default_memory_limit /= 8;
|
| -
|
| -#if defined(OS_LINUX)
|
| - base::FilePath shmem_dir;
|
| - if (base::GetShmemTempDir(false, &shmem_dir)) {
|
| - int64_t shmem_dir_amount_of_free_space =
|
| - base::SysInfo::AmountOfFreeDiskSpace(shmem_dir);
|
| - DCHECK_GT(shmem_dir_amount_of_free_space, 0);
|
| - int64_t shmem_dir_amount_of_free_space_mb =
|
| - shmem_dir_amount_of_free_space / kMegabyte;
|
| -
|
| - UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.ShmemDir.AmountOfFreeSpace",
|
| - shmem_dir_amount_of_free_space_mb, 1,
|
| - 4 * 1024, // 4 GB
|
| - 50);
|
| -
|
| - if (shmem_dir_amount_of_free_space_mb < 64) {
|
| - LOG(WARNING) << "Less than 64MB of free space in temporary directory for "
|
| - "shared memory files: "
|
| - << shmem_dir_amount_of_free_space_mb;
|
| - }
|
| -
|
| - // Allow 1/2 of available shmem dir space to be used for discardable memory.
|
| - max_default_memory_limit =
|
| - std::min(max_default_memory_limit, shmem_dir_amount_of_free_space / 2);
|
| - }
|
| -#endif
|
| -
|
| - // Allow 25% of physical memory to be used for discardable memory.
|
| - return std::min(max_default_memory_limit,
|
| - base::SysInfo::AmountOfPhysicalMemory() / 4);
|
| -}
|
| -
|
| -base::LazyInstance<HostDiscardableSharedMemoryManager>
|
| - g_discardable_shared_memory_manager = LAZY_INSTANCE_INITIALIZER;
|
| -
|
| -const int kEnforceMemoryPolicyDelayMs = 1000;
|
| -
|
| -// Global atomic to generate unique discardable shared memory IDs.
|
| -base::StaticAtomicSequenceNumber g_next_discardable_shared_memory_id;
|
| -
|
| -} // namespace
|
| -
|
| -HostDiscardableSharedMemoryManager::MemorySegment::MemorySegment(
|
| - std::unique_ptr<base::DiscardableSharedMemory> memory)
|
| - : memory_(std::move(memory)) {}
|
| -
|
| -HostDiscardableSharedMemoryManager::MemorySegment::~MemorySegment() {
|
| -}
|
| -
|
| -HostDiscardableSharedMemoryManager::HostDiscardableSharedMemoryManager()
|
| - : default_memory_limit_(GetDefaultMemoryLimit()),
|
| - memory_limit_(default_memory_limit_),
|
| - bytes_allocated_(0),
|
| - memory_pressure_listener_(new base::MemoryPressureListener(
|
| - base::Bind(&HostDiscardableSharedMemoryManager::OnMemoryPressure,
|
| - base::Unretained(this)))),
|
| - // Current thread might not have a task runner in tests.
|
| - enforce_memory_policy_task_runner_(base::ThreadTaskRunnerHandle::Get()),
|
| - enforce_memory_policy_pending_(false),
|
| - weak_ptr_factory_(this) {
|
| - DCHECK_NE(memory_limit_, 0u);
|
| - enforce_memory_policy_callback_ =
|
| - base::Bind(&HostDiscardableSharedMemoryManager::EnforceMemoryPolicy,
|
| - weak_ptr_factory_.GetWeakPtr());
|
| - base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
|
| - this, "HostDiscardableSharedMemoryManager",
|
| - base::ThreadTaskRunnerHandle::Get());
|
| - base::MemoryCoordinatorClientRegistry::GetInstance()->Register(this);
|
| -}
|
| -
|
| -HostDiscardableSharedMemoryManager::~HostDiscardableSharedMemoryManager() {
|
| - base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
|
| - this);
|
| -}
|
| -
|
| -HostDiscardableSharedMemoryManager*
|
| -HostDiscardableSharedMemoryManager::current() {
|
| - return g_discardable_shared_memory_manager.Pointer();
|
| -}
|
| -
|
| -std::unique_ptr<base::DiscardableMemory>
|
| -HostDiscardableSharedMemoryManager::AllocateLockedDiscardableMemory(
|
| - size_t size) {
|
| - DCHECK_NE(size, 0u);
|
| -
|
| - DiscardableSharedMemoryId new_id =
|
| - g_next_discardable_shared_memory_id.GetNext();
|
| - base::ProcessHandle current_process_handle = base::GetCurrentProcessHandle();
|
| -
|
| - // Note: Use DiscardableSharedMemoryHeap for in-process allocation
|
| - // of discardable memory if the cost of each allocation is too high.
|
| - base::SharedMemoryHandle handle;
|
| - AllocateLockedDiscardableSharedMemory(current_process_handle,
|
| - ChildProcessHost::kInvalidUniqueID,
|
| - size, new_id, &handle);
|
| - std::unique_ptr<base::DiscardableSharedMemory> memory(
|
| - new base::DiscardableSharedMemory(handle));
|
| - if (!memory->Map(size))
|
| - base::TerminateBecauseOutOfMemory(size);
|
| - // Close file descriptor to avoid running out.
|
| - memory->Close();
|
| - return base::MakeUnique<DiscardableMemoryImpl>(
|
| - std::move(memory),
|
| - base::Bind(
|
| - &HostDiscardableSharedMemoryManager::DeletedDiscardableSharedMemory,
|
| - base::Unretained(this), new_id, ChildProcessHost::kInvalidUniqueID));
|
| -}
|
| -
|
| -bool HostDiscardableSharedMemoryManager::OnMemoryDump(
|
| - const base::trace_event::MemoryDumpArgs& args,
|
| - base::trace_event::ProcessMemoryDump* pmd) {
|
| - if (args.level_of_detail ==
|
| - base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND) {
|
| - base::trace_event::MemoryAllocatorDump* total_dump =
|
| - pmd->CreateAllocatorDump("discardable");
|
| - total_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
|
| - base::trace_event::MemoryAllocatorDump::kUnitsBytes,
|
| - GetBytesAllocated());
|
| - return true;
|
| - }
|
| -
|
| - base::AutoLock lock(lock_);
|
| - for (const auto& process_entry : processes_) {
|
| - const int child_process_id = process_entry.first;
|
| - const MemorySegmentMap& process_segments = process_entry.second;
|
| - for (const auto& segment_entry : process_segments) {
|
| - const int segment_id = segment_entry.first;
|
| - const MemorySegment* segment = segment_entry.second.get();
|
| - if (!segment->memory()->mapped_size())
|
| - continue;
|
| -
|
| - // The "size" will be inherited form the shared global dump.
|
| - std::string dump_name = base::StringPrintf(
|
| - "discardable/process_%x/segment_%d", child_process_id, segment_id);
|
| - base::trace_event::MemoryAllocatorDump* dump =
|
| - pmd->CreateAllocatorDump(dump_name);
|
| -
|
| - dump->AddScalar("virtual_size",
|
| - base::trace_event::MemoryAllocatorDump::kUnitsBytes,
|
| - segment->memory()->mapped_size());
|
| -
|
| - // Host can only tell if whole segment is locked or not.
|
| - dump->AddScalar(
|
| - "locked_size", base::trace_event::MemoryAllocatorDump::kUnitsBytes,
|
| - segment->memory()->IsMemoryLocked() ? segment->memory()->mapped_size()
|
| - : 0u);
|
| -
|
| - // Create the cross-process ownership edge. If the child creates a
|
| - // corresponding dump for the same segment, this will avoid to
|
| - // double-count them in tracing. If, instead, no other process will emit a
|
| - // dump with the same guid, the segment will be accounted to the browser.
|
| - const uint64_t child_tracing_process_id =
|
| - ChildProcessHostImpl::ChildProcessUniqueIdToTracingProcessId(
|
| - child_process_id);
|
| - base::trace_event::MemoryAllocatorDumpGuid shared_segment_guid =
|
| - DiscardableSharedMemoryHeap::GetSegmentGUIDForTracing(
|
| - child_tracing_process_id, segment_id);
|
| - pmd->CreateSharedGlobalAllocatorDump(shared_segment_guid);
|
| - pmd->AddOwnershipEdge(dump->guid(), shared_segment_guid);
|
| -
|
| -#if defined(COUNT_RESIDENT_BYTES_SUPPORTED)
|
| - if (args.level_of_detail ==
|
| - base::trace_event::MemoryDumpLevelOfDetail::DETAILED) {
|
| - size_t resident_size =
|
| - base::trace_event::ProcessMemoryDump::CountResidentBytes(
|
| - segment->memory()->memory(), segment->memory()->mapped_size());
|
| -
|
| - // This is added to the global dump since it has to be attributed to
|
| - // both the allocator dumps involved.
|
| - pmd->GetSharedGlobalAllocatorDump(shared_segment_guid)
|
| - ->AddScalar("resident_size",
|
| - base::trace_event::MemoryAllocatorDump::kUnitsBytes,
|
| - static_cast<uint64_t>(resident_size));
|
| - }
|
| -#endif // defined(COUNT_RESIDENT_BYTES_SUPPORTED)
|
| - }
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -void HostDiscardableSharedMemoryManager::
|
| - AllocateLockedDiscardableSharedMemoryForChild(
|
| - base::ProcessHandle process_handle,
|
| - int child_process_id,
|
| - size_t size,
|
| - DiscardableSharedMemoryId id,
|
| - base::SharedMemoryHandle* shared_memory_handle) {
|
| - AllocateLockedDiscardableSharedMemory(process_handle, child_process_id, size,
|
| - id, shared_memory_handle);
|
| -}
|
| -
|
| -void HostDiscardableSharedMemoryManager::ChildDeletedDiscardableSharedMemory(
|
| - DiscardableSharedMemoryId id,
|
| - int child_process_id) {
|
| - DeletedDiscardableSharedMemory(id, child_process_id);
|
| -}
|
| -
|
| -void HostDiscardableSharedMemoryManager::ProcessRemoved(int child_process_id) {
|
| - base::AutoLock lock(lock_);
|
| -
|
| - ProcessMap::iterator process_it = processes_.find(child_process_id);
|
| - if (process_it == processes_.end())
|
| - return;
|
| -
|
| - size_t bytes_allocated_before_releasing_memory = bytes_allocated_;
|
| -
|
| - for (auto& segment_it : process_it->second)
|
| - ReleaseMemory(segment_it.second->memory());
|
| -
|
| - processes_.erase(process_it);
|
| -
|
| - if (bytes_allocated_ != bytes_allocated_before_releasing_memory)
|
| - BytesAllocatedChanged(bytes_allocated_);
|
| -}
|
| -
|
| -void HostDiscardableSharedMemoryManager::SetMemoryLimit(size_t limit) {
|
| - base::AutoLock lock(lock_);
|
| -
|
| - memory_limit_ = limit;
|
| - ReduceMemoryUsageUntilWithinMemoryLimit();
|
| -}
|
| -
|
| -void HostDiscardableSharedMemoryManager::EnforceMemoryPolicy() {
|
| - base::AutoLock lock(lock_);
|
| -
|
| - enforce_memory_policy_pending_ = false;
|
| - ReduceMemoryUsageUntilWithinMemoryLimit();
|
| -}
|
| -
|
| -size_t HostDiscardableSharedMemoryManager::GetBytesAllocated() {
|
| - base::AutoLock lock(lock_);
|
| -
|
| - return bytes_allocated_;
|
| -}
|
| -
|
| -void HostDiscardableSharedMemoryManager::OnMemoryStateChange(
|
| - base::MemoryState state) {
|
| - switch (state) {
|
| - case base::MemoryState::NORMAL:
|
| - SetMemoryLimit(default_memory_limit_);
|
| - break;
|
| - case base::MemoryState::THROTTLED:
|
| - SetMemoryLimit(0);
|
| - break;
|
| - case base::MemoryState::SUSPENDED:
|
| - // Note that SUSPENDED never occurs in the main browser process so far.
|
| - // Fall through.
|
| - case base::MemoryState::UNKNOWN:
|
| - NOTREACHED();
|
| - break;
|
| - }
|
| -}
|
| -
|
| -void HostDiscardableSharedMemoryManager::AllocateLockedDiscardableSharedMemory(
|
| - base::ProcessHandle process_handle,
|
| - int client_process_id,
|
| - size_t size,
|
| - DiscardableSharedMemoryId id,
|
| - base::SharedMemoryHandle* shared_memory_handle) {
|
| - base::AutoLock lock(lock_);
|
| -
|
| - // Make sure |id| is not already in use.
|
| - MemorySegmentMap& process_segments = processes_[client_process_id];
|
| - if (process_segments.find(id) != process_segments.end()) {
|
| - LOG(ERROR) << "Invalid discardable shared memory ID";
|
| - *shared_memory_handle = base::SharedMemory::NULLHandle();
|
| - return;
|
| - }
|
| -
|
| - // Memory usage must be reduced to prevent the addition of |size| from
|
| - // taking usage above the limit. Usage should be reduced to 0 in cases
|
| - // where |size| is greater than the limit.
|
| - size_t limit = 0;
|
| - // Note: the actual mapped size can be larger than requested and cause
|
| - // |bytes_allocated_| to temporarily be larger than |memory_limit_|. The
|
| - // error is minimized by incrementing |bytes_allocated_| with the actual
|
| - // mapped size rather than |size| below.
|
| - if (size < memory_limit_)
|
| - limit = memory_limit_ - size;
|
| -
|
| - if (bytes_allocated_ > limit)
|
| - ReduceMemoryUsageUntilWithinLimit(limit);
|
| -
|
| - std::unique_ptr<base::DiscardableSharedMemory> memory(
|
| - new base::DiscardableSharedMemory);
|
| - if (!memory->CreateAndMap(size)) {
|
| - *shared_memory_handle = base::SharedMemory::NULLHandle();
|
| - return;
|
| - }
|
| -
|
| - if (!memory->ShareToProcess(process_handle, shared_memory_handle)) {
|
| - LOG(ERROR) << "Cannot share discardable memory segment";
|
| - *shared_memory_handle = base::SharedMemory::NULLHandle();
|
| - return;
|
| - }
|
| -
|
| - // Close file descriptor to avoid running out.
|
| - memory->Close();
|
| -
|
| - base::CheckedNumeric<size_t> checked_bytes_allocated = bytes_allocated_;
|
| - checked_bytes_allocated += memory->mapped_size();
|
| - if (!checked_bytes_allocated.IsValid()) {
|
| - *shared_memory_handle = base::SharedMemory::NULLHandle();
|
| - return;
|
| - }
|
| -
|
| - bytes_allocated_ = checked_bytes_allocated.ValueOrDie();
|
| - BytesAllocatedChanged(bytes_allocated_);
|
| -
|
| - scoped_refptr<MemorySegment> segment(new MemorySegment(std::move(memory)));
|
| - process_segments[id] = segment.get();
|
| - segments_.push_back(segment.get());
|
| - std::push_heap(segments_.begin(), segments_.end(), CompareMemoryUsageTime);
|
| -
|
| - if (bytes_allocated_ > memory_limit_)
|
| - ScheduleEnforceMemoryPolicy();
|
| -}
|
| -
|
| -void HostDiscardableSharedMemoryManager::DeletedDiscardableSharedMemory(
|
| - DiscardableSharedMemoryId id,
|
| - int client_process_id) {
|
| - base::AutoLock lock(lock_);
|
| -
|
| - MemorySegmentMap& process_segments = processes_[client_process_id];
|
| -
|
| - MemorySegmentMap::iterator segment_it = process_segments.find(id);
|
| - if (segment_it == process_segments.end()) {
|
| - LOG(ERROR) << "Invalid discardable shared memory ID";
|
| - return;
|
| - }
|
| -
|
| - size_t bytes_allocated_before_releasing_memory = bytes_allocated_;
|
| -
|
| - ReleaseMemory(segment_it->second->memory());
|
| -
|
| - process_segments.erase(segment_it);
|
| -
|
| - if (bytes_allocated_ != bytes_allocated_before_releasing_memory)
|
| - BytesAllocatedChanged(bytes_allocated_);
|
| -}
|
| -
|
| -void HostDiscardableSharedMemoryManager::OnMemoryPressure(
|
| - base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
|
| - base::AutoLock lock(lock_);
|
| -
|
| - switch (memory_pressure_level) {
|
| - case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
|
| - break;
|
| - case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
|
| - // Purge memory until usage is within half of |memory_limit_|.
|
| - ReduceMemoryUsageUntilWithinLimit(memory_limit_ / 2);
|
| - break;
|
| - case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
|
| - // Purge everything possible when pressure is critical.
|
| - ReduceMemoryUsageUntilWithinLimit(0);
|
| - break;
|
| - }
|
| -}
|
| -
|
| -void
|
| -HostDiscardableSharedMemoryManager::ReduceMemoryUsageUntilWithinMemoryLimit() {
|
| - lock_.AssertAcquired();
|
| -
|
| - if (bytes_allocated_ <= memory_limit_)
|
| - return;
|
| -
|
| - ReduceMemoryUsageUntilWithinLimit(memory_limit_);
|
| - if (bytes_allocated_ > memory_limit_)
|
| - ScheduleEnforceMemoryPolicy();
|
| -}
|
| -
|
| -void HostDiscardableSharedMemoryManager::ReduceMemoryUsageUntilWithinLimit(
|
| - size_t limit) {
|
| - TRACE_EVENT1("renderer_host",
|
| - "HostDiscardableSharedMemoryManager::"
|
| - "ReduceMemoryUsageUntilWithinLimit",
|
| - "bytes_allocated",
|
| - bytes_allocated_);
|
| -
|
| - // Usage time of currently locked segments are updated to this time and
|
| - // we stop eviction attempts as soon as we come across a segment that we've
|
| - // previously tried to evict but was locked.
|
| - base::Time current_time = Now();
|
| -
|
| - lock_.AssertAcquired();
|
| - size_t bytes_allocated_before_purging = bytes_allocated_;
|
| - while (!segments_.empty()) {
|
| - if (bytes_allocated_ <= limit)
|
| - break;
|
| -
|
| - // Stop eviction attempts when the LRU segment is currently in use.
|
| - if (segments_.front()->memory()->last_known_usage() >= current_time)
|
| - break;
|
| -
|
| - std::pop_heap(segments_.begin(), segments_.end(), CompareMemoryUsageTime);
|
| - scoped_refptr<MemorySegment> segment = segments_.back();
|
| - segments_.pop_back();
|
| -
|
| - // Simply drop the reference and continue if memory has already been
|
| - // unmapped. This happens when a memory segment has been deleted by
|
| - // the client.
|
| - if (!segment->memory()->mapped_size())
|
| - continue;
|
| -
|
| - // Attempt to purge LRU segment. When successful, released the memory.
|
| - if (segment->memory()->Purge(current_time)) {
|
| - ReleaseMemory(segment->memory());
|
| - continue;
|
| - }
|
| -
|
| - // Add memory segment (with updated usage timestamp) back on heap after
|
| - // failed attempt to purge it.
|
| - segments_.push_back(segment.get());
|
| - std::push_heap(segments_.begin(), segments_.end(), CompareMemoryUsageTime);
|
| - }
|
| -
|
| - if (bytes_allocated_ != bytes_allocated_before_purging)
|
| - BytesAllocatedChanged(bytes_allocated_);
|
| -}
|
| -
|
| -void HostDiscardableSharedMemoryManager::ReleaseMemory(
|
| - base::DiscardableSharedMemory* memory) {
|
| - lock_.AssertAcquired();
|
| -
|
| - size_t size = memory->mapped_size();
|
| - DCHECK_GE(bytes_allocated_, size);
|
| - bytes_allocated_ -= size;
|
| -
|
| - // This will unmap the memory segment and drop our reference. The result
|
| - // is that the memory will be released to the OS if the child process is
|
| - // no longer referencing it.
|
| - // Note: We intentionally leave the segment in the |segments| vector to
|
| - // avoid reconstructing the heap. The element will be removed from the heap
|
| - // when its last usage time is older than all other segments.
|
| - memory->Unmap();
|
| - memory->Close();
|
| -}
|
| -
|
| -void HostDiscardableSharedMemoryManager::BytesAllocatedChanged(
|
| - size_t new_bytes_allocated) const {
|
| - static const char kTotalDiscardableMemoryAllocatedKey[] =
|
| - "total-discardable-memory-allocated";
|
| - base::debug::SetCrashKeyValue(kTotalDiscardableMemoryAllocatedKey,
|
| - base::Uint64ToString(new_bytes_allocated));
|
| -}
|
| -
|
| -base::Time HostDiscardableSharedMemoryManager::Now() const {
|
| - return base::Time::Now();
|
| -}
|
| -
|
| -void HostDiscardableSharedMemoryManager::ScheduleEnforceMemoryPolicy() {
|
| - lock_.AssertAcquired();
|
| -
|
| - if (enforce_memory_policy_pending_)
|
| - return;
|
| -
|
| - enforce_memory_policy_pending_ = true;
|
| - DCHECK(enforce_memory_policy_task_runner_);
|
| - enforce_memory_policy_task_runner_->PostDelayedTask(
|
| - FROM_HERE, enforce_memory_policy_callback_,
|
| - base::TimeDelta::FromMilliseconds(kEnforceMemoryPolicyDelayMs));
|
| -}
|
| -
|
| -} // namespace content
|
|
|