Don't preload rarely seen large images
[chromium-blink-merge.git] / components / html_viewer / discardable_memory_allocator.cc
blob7f362239b2d5f0c4bebd6be4c01913b4f0ee06a4
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"
10 namespace html_viewer {
12 // Interface to the rest of the program. These objects are owned outside of the
13 // allocator.
14 class DiscardableMemoryAllocator::DiscardableMemoryChunkImpl
15 : public base::DiscardableMemory {
16 public:
17 DiscardableMemoryChunkImpl(size_t size, DiscardableMemoryAllocator* allocator)
18 : is_locked_(true),
19 size_(size),
20 data_(new uint8_t[size]),
21 allocator_(allocator) {}
23 ~DiscardableMemoryChunkImpl() override {
24 // Either the memory is discarded or the memory chunk is unlocked.
25 DCHECK(data_ || !is_locked_);
26 if (!is_locked_ && data_)
27 allocator_->NotifyDestructed(unlocked_position_);
30 // Overridden from DiscardableMemoryChunk:
31 bool Lock() override {
32 DCHECK(!is_locked_);
33 if (!data_)
34 return false;
36 is_locked_ = true;
37 allocator_->NotifyLocked(unlocked_position_);
38 return true;
41 void Unlock() override {
42 DCHECK(is_locked_);
43 DCHECK(data_);
44 is_locked_ = false;
45 unlocked_position_ = allocator_->NotifyUnlocked(this);
48 void* data() const override {
49 if (data_) {
50 DCHECK(is_locked_);
51 return data_.get();
53 return nullptr;
56 size_t size() const { return size_; }
58 void Discard() {
59 DCHECK(!is_locked_);
60 data_.reset();
63 private:
64 bool is_locked_;
65 size_t size_;
66 scoped_ptr<uint8_t[]> data_;
67 DiscardableMemoryAllocator* allocator_;
69 std::list<DiscardableMemoryChunkImpl*>::iterator unlocked_position_;
71 DISALLOW_IMPLICIT_CONSTRUCTORS(DiscardableMemoryChunkImpl);
74 DiscardableMemoryAllocator::DiscardableMemoryAllocator(
75 size_t desired_max_memory)
76 : desired_max_memory_(desired_max_memory),
77 total_live_memory_(0u),
78 locked_chunks_(0) {
81 DiscardableMemoryAllocator::~DiscardableMemoryAllocator() {
82 DCHECK_EQ(0, locked_chunks_);
83 STLDeleteElements(&live_unlocked_chunks_);
86 scoped_ptr<base::DiscardableMemory>
87 DiscardableMemoryAllocator::AllocateLockedDiscardableMemory(size_t size) {
88 base::AutoLock lock(lock_);
89 scoped_ptr<DiscardableMemoryChunkImpl> chunk(
90 new DiscardableMemoryChunkImpl(size, this));
91 total_live_memory_ += size;
92 locked_chunks_++;
94 // Go through the list of unlocked live chunks starting from the least
95 // recently used, freeing as many as we can until we get our size under the
96 // desired maximum.
97 auto it = live_unlocked_chunks_.begin();
98 while (total_live_memory_ > desired_max_memory_ &&
99 it != live_unlocked_chunks_.end()) {
100 total_live_memory_ -= (*it)->size();
101 (*it)->Discard();
102 it = live_unlocked_chunks_.erase(it);
105 return chunk.Pass();
108 std::list<DiscardableMemoryAllocator::DiscardableMemoryChunkImpl*>::iterator
109 DiscardableMemoryAllocator::NotifyUnlocked(DiscardableMemoryChunkImpl* chunk) {
110 base::AutoLock lock(lock_);
111 locked_chunks_--;
112 return live_unlocked_chunks_.insert(live_unlocked_chunks_.end(), chunk);
115 void DiscardableMemoryAllocator::NotifyLocked(
116 std::list<DiscardableMemoryChunkImpl*>::iterator it) {
117 base::AutoLock lock(lock_);
118 locked_chunks_++;
119 live_unlocked_chunks_.erase(it);
122 void DiscardableMemoryAllocator::NotifyDestructed(
123 std::list<DiscardableMemoryChunkImpl*>::iterator it) {
124 base::AutoLock lock(lock_);
125 live_unlocked_chunks_.erase(it);
128 } // namespace html_viewer