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

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: disable DCHECK 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..ab56445bfb6c97a38e567b550644111e2bb51cfd 100644
--- a/content/common/discardable_shared_memory_heap.cc
+++ b/content/common/discardable_shared_memory_heap.cc
@@ -29,16 +29,37 @@ DiscardableSharedMemoryHeap::Span::Span(
DiscardableSharedMemoryHeap::Span::~Span() {
}
+DiscardableSharedMemoryHeap::ScopedMemorySegment::ScopedMemorySegment(
+ DiscardableSharedMemoryHeap* heap,
+ scoped_ptr<base::DiscardableSharedMemory> shared_memory,
+ size_t size)
+ : heap_(heap), shared_memory_(shared_memory.Pass()), size_(size) {
+}
+
+DiscardableSharedMemoryHeap::ScopedMemorySegment::~ScopedMemorySegment() {
+ heap_->ReleaseMemory(shared_memory_.get(), size_);
+ // 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(), size_);
+}
+
+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);
DCHECK(free_spans_.empty());
}
@@ -59,9 +80,11 @@ scoped_ptr<DiscardableSharedMemoryHeap::Span> DiscardableSharedMemoryHeap::Grow(
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(
+ new ScopedMemorySegment(this, shared_memory.Pass(), size));
return span.Pass();
}
@@ -69,6 +92,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 +168,33 @@ 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() {
+ // Erase all free segments after rearranging the segments in such a way
+ // that used segments precede all free segments.
+ memory_segments_.erase(
+ std::partition(
+ memory_segments_.begin(), memory_segments_.end(),
+ [](const ScopedMemorySegment* segment) { return segment->IsUsed(); }),
+ memory_segments_.end());
+}
- // Release the memory and unregistering all associated spans.
- ReleaseMemory(shared_memory);
+void DiscardableSharedMemoryHeap::ReleasePurgedMemory() {
+ // Erase all purged segments after rearranging the segments in such a way
+ // that resident segments precede all purged segments.
+ memory_segments_.erase(
+ std::partition(memory_segments_.begin(), memory_segments_.end(),
+ [](const 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 +223,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,11 +248,30 @@ void DiscardableSharedMemoryHeap::UnregisterSpan(Span* span) {
}
}
+bool DiscardableSharedMemoryHeap::IsMemoryUsed(
+ const base::DiscardableSharedMemory* shared_memory,
+ size_t size) {
+ size_t offset =
+ reinterpret_cast<size_t>(shared_memory->memory()) / block_size_;
+ size_t length = 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 size) {
size_t offset =
reinterpret_cast<size_t>(shared_memory->memory()) / block_size_;
- size_t end = offset + shared_memory->mapped_size() / block_size_;
+ size_t end = offset + size / block_size_;
while (offset < end) {
DCHECK(spans_.find(offset) != spans_.end());
Span* span = spans_[offset];
@@ -228,9 +281,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);
+ }
}
}
« no previous file with comments | « content/common/discardable_shared_memory_heap.h ('k') | content/common/discardable_shared_memory_heap_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698