1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/html_viewer/discardable_memory_allocator.h"
7 #include "base/memory/discardable_memory.h"
8 #include "base/stl_util.h"
9 #include "base/trace_event/memory_allocator_dump.h"
10 #include "base/trace_event/memory_dump_manager.h"
11 #include "base/trace_event/process_memory_dump.h"
13 namespace html_viewer
{
15 // Interface to the rest of the program. These objects are owned outside of the
17 class DiscardableMemoryAllocator::DiscardableMemoryChunkImpl
18 : public base::DiscardableMemory
{
20 DiscardableMemoryChunkImpl(size_t size
, DiscardableMemoryAllocator
* allocator
)
23 data_(new uint8_t[size
]),
24 allocator_(allocator
) {}
26 ~DiscardableMemoryChunkImpl() override
{
27 // Either the memory is discarded or the memory chunk is unlocked.
28 DCHECK(data_
|| !is_locked_
);
29 if (!is_locked_
&& data_
)
30 allocator_
->NotifyDestructed(unlocked_position_
);
33 // Overridden from DiscardableMemoryChunk:
34 bool Lock() override
{
40 allocator_
->NotifyLocked(unlocked_position_
);
44 void Unlock() override
{
48 unlocked_position_
= allocator_
->NotifyUnlocked(this);
51 void* data() const override
{
59 base::trace_event::MemoryAllocatorDump
* CreateMemoryAllocatorDump(
61 base::trace_event::ProcessMemoryDump
* pmd
) const override
{
62 base::trace_event::MemoryAllocatorDump
* dump
=
63 pmd
->CreateAllocatorDump(name
);
64 dump
->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize
,
65 base::trace_event::MemoryAllocatorDump::kUnitsBytes
, size_
);
67 // Memory is allocated from system allocator (malloc).
68 pmd
->AddSuballocation(dump
->guid(),
69 base::trace_event::MemoryDumpManager::GetInstance()
70 ->system_allocator_pool_name());
74 size_t size() const { return size_
; }
84 scoped_ptr
<uint8_t[]> data_
;
85 DiscardableMemoryAllocator
* allocator_
;
87 std::list
<DiscardableMemoryChunkImpl
*>::iterator unlocked_position_
;
89 DISALLOW_IMPLICIT_CONSTRUCTORS(DiscardableMemoryChunkImpl
);
92 DiscardableMemoryAllocator::DiscardableMemoryAllocator(
93 size_t desired_max_memory
)
94 : desired_max_memory_(desired_max_memory
),
95 total_live_memory_(0u),
99 DiscardableMemoryAllocator::~DiscardableMemoryAllocator() {
100 DCHECK_EQ(0, locked_chunks_
);
101 STLDeleteElements(&live_unlocked_chunks_
);
104 scoped_ptr
<base::DiscardableMemory
>
105 DiscardableMemoryAllocator::AllocateLockedDiscardableMemory(size_t size
) {
106 base::AutoLock
lock(lock_
);
107 scoped_ptr
<DiscardableMemoryChunkImpl
> chunk(
108 new DiscardableMemoryChunkImpl(size
, this));
109 total_live_memory_
+= size
;
112 // Go through the list of unlocked live chunks starting from the least
113 // recently used, freeing as many as we can until we get our size under the
115 auto it
= live_unlocked_chunks_
.begin();
116 while (total_live_memory_
> desired_max_memory_
&&
117 it
!= live_unlocked_chunks_
.end()) {
118 total_live_memory_
-= (*it
)->size();
120 it
= live_unlocked_chunks_
.erase(it
);
126 std::list
<DiscardableMemoryAllocator::DiscardableMemoryChunkImpl
*>::iterator
127 DiscardableMemoryAllocator::NotifyUnlocked(DiscardableMemoryChunkImpl
* chunk
) {
128 base::AutoLock
lock(lock_
);
130 return live_unlocked_chunks_
.insert(live_unlocked_chunks_
.end(), chunk
);
133 void DiscardableMemoryAllocator::NotifyLocked(
134 std::list
<DiscardableMemoryChunkImpl
*>::iterator it
) {
135 base::AutoLock
lock(lock_
);
137 live_unlocked_chunks_
.erase(it
);
140 void DiscardableMemoryAllocator::NotifyDestructed(
141 std::list
<DiscardableMemoryChunkImpl
*>::iterator it
) {
142 base::AutoLock
lock(lock_
);
143 live_unlocked_chunks_
.erase(it
);
146 } // namespace html_viewer