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 base::AutoLock
lock(allocator_
->lock_
);
28 // Either the memory is discarded or the memory chunk is unlocked.
29 DCHECK(data_
|| !is_locked_
);
30 if (!is_locked_
&& data_
)
31 allocator_
->NotifyDestructed(unlocked_position_
);
34 // Overridden from DiscardableMemoryChunk:
35 bool Lock() override
{
36 base::AutoLock
lock(allocator_
->lock_
);
42 allocator_
->NotifyLocked(unlocked_position_
);
46 void Unlock() override
{
47 base::AutoLock
lock(allocator_
->lock_
);
51 unlocked_position_
= allocator_
->NotifyUnlocked(this);
54 void* data() const override
{
62 base::trace_event::MemoryAllocatorDump
* CreateMemoryAllocatorDump(
64 base::trace_event::ProcessMemoryDump
* pmd
) const override
{
65 base::trace_event::MemoryAllocatorDump
* dump
=
66 pmd
->CreateAllocatorDump(name
);
67 dump
->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize
,
68 base::trace_event::MemoryAllocatorDump::kUnitsBytes
, size_
);
70 // Memory is allocated from system allocator (malloc).
71 pmd
->AddSuballocation(dump
->guid(),
72 base::trace_event::MemoryDumpManager::GetInstance()
73 ->system_allocator_pool_name());
77 size_t size() const { return size_
; }
80 allocator_
->lock_
.AssertAcquired();
88 scoped_ptr
<uint8_t[]> data_
;
89 DiscardableMemoryAllocator
* allocator_
;
91 std::list
<DiscardableMemoryChunkImpl
*>::iterator unlocked_position_
;
93 DISALLOW_IMPLICIT_CONSTRUCTORS(DiscardableMemoryChunkImpl
);
96 DiscardableMemoryAllocator::DiscardableMemoryAllocator(
97 size_t desired_max_memory
)
98 : desired_max_memory_(desired_max_memory
),
99 total_live_memory_(0u),
103 DiscardableMemoryAllocator::~DiscardableMemoryAllocator() {
104 DCHECK_EQ(0, locked_chunks_
);
105 STLDeleteElements(&live_unlocked_chunks_
);
108 scoped_ptr
<base::DiscardableMemory
>
109 DiscardableMemoryAllocator::AllocateLockedDiscardableMemory(size_t size
) {
110 base::AutoLock
lock(lock_
);
111 scoped_ptr
<DiscardableMemoryChunkImpl
> chunk(
112 new DiscardableMemoryChunkImpl(size
, this));
113 total_live_memory_
+= size
;
116 // Go through the list of unlocked live chunks starting from the least
117 // recently used, freeing as many as we can until we get our size under the
119 auto it
= live_unlocked_chunks_
.begin();
120 while (total_live_memory_
> desired_max_memory_
&&
121 it
!= live_unlocked_chunks_
.end()) {
122 total_live_memory_
-= (*it
)->size();
124 it
= live_unlocked_chunks_
.erase(it
);
130 std::list
<DiscardableMemoryAllocator::DiscardableMemoryChunkImpl
*>::iterator
131 DiscardableMemoryAllocator::NotifyUnlocked(DiscardableMemoryChunkImpl
* chunk
) {
132 lock_
.AssertAcquired();
134 return live_unlocked_chunks_
.insert(live_unlocked_chunks_
.end(), chunk
);
137 void DiscardableMemoryAllocator::NotifyLocked(
138 std::list
<DiscardableMemoryChunkImpl
*>::iterator it
) {
139 lock_
.AssertAcquired();
141 live_unlocked_chunks_
.erase(it
);
144 void DiscardableMemoryAllocator::NotifyDestructed(
145 std::list
<DiscardableMemoryChunkImpl
*>::iterator it
) {
146 lock_
.AssertAcquired();
147 live_unlocked_chunks_
.erase(it
);
150 } // namespace html_viewer