Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(669)

Unified Diff: content/common/discardable_shared_memory_heap.cc

Issue 981403002: content: Release all free discardable memory when idle. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: add missing include Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/common/discardable_shared_memory_heap.cc
diff --git a/content/common/discardable_shared_memory_heap.cc b/content/common/discardable_shared_memory_heap.cc
index fc00ea300b95df236d885c68e7d93527b73d7bd2..94d8d3118b6e6831ff53ec62964f58f052563870 100644
--- a/content/common/discardable_shared_memory_heap.cc
+++ b/content/common/discardable_shared_memory_heap.cc
@@ -29,39 +29,60 @@ DiscardableSharedMemoryHeap::Span::Span(
DiscardableSharedMemoryHeap::Span::~Span() {
}
+DiscardableSharedMemoryHeap::ScopedMemorySegment::ScopedMemorySegment(
+ scoped_ptr<base::DiscardableSharedMemory> shared_memory,
+ DiscardableSharedMemoryHeap* heap)
+ : shared_memory_(shared_memory.Pass()), heap_(heap) {
+}
+
+DiscardableSharedMemoryHeap::ScopedMemorySegment::~ScopedMemorySegment() {
+ heap_->ReleaseMemory(shared_memory_.get());
+ // Purge memory. This has no effect if already purged.
+ shared_memory_->Purge(base::Time::Now());
+}
+
+bool DiscardableSharedMemoryHeap::ScopedMemorySegment::IsUsed() const {
+ return heap_->IsMemoryUsed(shared_memory_.get());
+}
+
+bool DiscardableSharedMemoryHeap::ScopedMemorySegment::IsResident() const {
+ return heap_->IsMemoryResident(shared_memory_.get());
+}
+
DiscardableSharedMemoryHeap::DiscardableSharedMemoryHeap(size_t block_size)
- : block_size_(block_size) {
+ : block_size_(block_size), num_blocks_(0), num_free_blocks_(0) {
DCHECK_NE(block_size_, 0u);
DCHECK(IsPowerOfTwo(block_size_));
}
DiscardableSharedMemoryHeap::~DiscardableSharedMemoryHeap() {
- for (auto shared_memory : shared_memory_segments_)
- ReleaseMemory(shared_memory);
-
+ memory_segments_.clear();
+ DCHECK_EQ(num_blocks_, 0u);
+ DCHECK_EQ(num_free_blocks_, 0u);
Avi (use Gerrit) 2015/03/09 16:03:37 Expected value as the first parameter.
DCHECK(free_spans_.empty());
}
scoped_ptr<DiscardableSharedMemoryHeap::Span> DiscardableSharedMemoryHeap::Grow(
- scoped_ptr<base::DiscardableSharedMemory> shared_memory,
- size_t size) {
+ scoped_ptr<base::DiscardableSharedMemory> shared_memory) {
// Memory must be aligned to block size.
DCHECK_EQ(
reinterpret_cast<size_t>(shared_memory->memory()) & (block_size_ - 1),
0u);
- DCHECK_EQ(size & (block_size_ - 1), 0u);
+ DCHECK_EQ(shared_memory->mapped_size() & (block_size_ - 1), 0u);
scoped_ptr<Span> span(
new Span(shared_memory.get(),
reinterpret_cast<size_t>(shared_memory->memory()) / block_size_,
- size / block_size_));
+ shared_memory->mapped_size() / block_size_));
DCHECK(spans_.find(span->start_) == spans_.end());
DCHECK(spans_.find(span->start_ + span->length_ - 1) == spans_.end());
RegisterSpan(span.get());
- // Start tracking if segment is resident by adding it to
- // |shared_memory_segments_|.
- shared_memory_segments_.push_back(shared_memory.release());
+ num_blocks_ += span->length_;
+
+ // Start tracking if segment is resident by adding it to |memory_segments_|.
+ memory_segments_.push_back(
+ make_linked_ptr(new ScopedMemorySegment(shared_memory.Pass(), this)));
return span.Pass();
}
@@ -69,6 +90,9 @@ scoped_ptr<DiscardableSharedMemoryHeap::Span> DiscardableSharedMemoryHeap::Grow(
void DiscardableSharedMemoryHeap::MergeIntoFreeList(scoped_ptr<Span> span) {
DCHECK(span->shared_memory_);
+ // First add length of |span| to |num_free_blocks_|.
+ num_free_blocks_ += span->length_;
+
// Merge with previous span if possible.
SpanMap::iterator prev_it = spans_.find(span->start_ - 1);
if (prev_it != spans_.end() && IsInFreeList(prev_it->second)) {
@@ -142,30 +166,30 @@ DiscardableSharedMemoryHeap::SearchFreeList(size_t blocks) {
return best ? Carve(best, blocks) : nullptr;
}
-size_t DiscardableSharedMemoryHeap::ReleaseFreeMemory() {
- size_t bytes_released = 0;
- size_t i = 0;
-
- // Release memory for all non-resident segments.
- while (i < shared_memory_segments_.size()) {
- base::DiscardableSharedMemory* shared_memory = shared_memory_segments_[i];
-
- // Skip segment if still resident.
- if (shared_memory->IsMemoryResident()) {
- ++i;
- continue;
- }
-
- bytes_released += shared_memory->mapped_size();
+void DiscardableSharedMemoryHeap::ReleaseFreeMemory() {
+ memory_segments_.erase(
+ std::remove_if(memory_segments_.begin(), memory_segments_.end(),
+ [](const linked_ptr<ScopedMemorySegment>& segment) {
+ return !segment->IsUsed();
+ }),
+ memory_segments_.end());
+}
- // Release the memory and unregistering all associated spans.
- ReleaseMemory(shared_memory);
+void DiscardableSharedMemoryHeap::ReleasePurgedMemory() {
+ memory_segments_.erase(
+ std::remove_if(memory_segments_.begin(), memory_segments_.end(),
+ [](const linked_ptr<ScopedMemorySegment>& segment) {
+ return !segment->IsResident();
+ }),
+ memory_segments_.end());
+}
- std::swap(shared_memory_segments_[i], shared_memory_segments_.back());
- shared_memory_segments_.pop_back();
- }
+size_t DiscardableSharedMemoryHeap::GetSize() const {
+ return num_blocks_ * block_size_;
+}
- return bytes_released;
+size_t DiscardableSharedMemoryHeap::GetFreeListSize() const {
+ return num_free_blocks_ * block_size_;
}
scoped_ptr<DiscardableSharedMemoryHeap::Span>
@@ -194,6 +218,11 @@ DiscardableSharedMemoryHeap::Carve(Span* span, size_t blocks) {
spans_[serving->start_ + blocks - 1] = serving.get();
}
+ // |serving| is no longer in the free list, remove its length from
+ // |num_free_blocks_|.
+ DCHECK_GE(num_free_blocks_, serving->length_);
+ num_free_blocks_ -= serving->length_;
+
return serving.Pass();
}
@@ -214,8 +243,25 @@ void DiscardableSharedMemoryHeap::UnregisterSpan(Span* span) {
}
}
+bool DiscardableSharedMemoryHeap::IsMemoryUsed(
+ const base::DiscardableSharedMemory* shared_memory) {
+ size_t offset =
+ reinterpret_cast<size_t>(shared_memory->memory()) / block_size_;
+ size_t length = shared_memory->mapped_size() / block_size_;
+ DCHECK(spans_.find(offset) != spans_.end());
+ Span* span = spans_[offset];
+ DCHECK_LE(span->length_, length);
+ // Memory is used if first span is not in free list or shorter than segment.
+ return !IsInFreeList(span) || span->length_ != length;
+}
+
+bool DiscardableSharedMemoryHeap::IsMemoryResident(
+ const base::DiscardableSharedMemory* shared_memory) {
+ return shared_memory->IsMemoryResident();
+}
+
void DiscardableSharedMemoryHeap::ReleaseMemory(
- base::DiscardableSharedMemory* shared_memory) {
+ const base::DiscardableSharedMemory* shared_memory) {
size_t offset =
reinterpret_cast<size_t>(shared_memory->memory()) / block_size_;
size_t end = offset + shared_memory->mapped_size() / block_size_;
@@ -228,9 +274,15 @@ void DiscardableSharedMemoryHeap::ReleaseMemory(
offset += span->length_;
- // If |span| is in the free list, remove it.
- if (IsInFreeList(span))
+ DCHECK_GE(num_blocks_, span->length_);
+ num_blocks_ -= span->length_;
+
+ // If |span| is in the free list, remove it and update |num_free_blocks_|.
+ if (IsInFreeList(span)) {
+ DCHECK_GE(num_free_blocks_, span->length_);
+ num_free_blocks_ -= span->length_;
RemoveFromFreeList(span);
+ }
}
}

Powered by Google App Engine
This is Rietveld 408576698