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); |
+ } |
} |
} |