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

Side by Side Diff: content/child/child_discardable_shared_memory_manager.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 unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/child/child_discardable_shared_memory_manager.h" 5 #include "content/child/child_discardable_shared_memory_manager.h"
6 6
7 #include "base/debug/crash_logging.h" 7 #include "base/debug/crash_logging.h"
8 #include "base/memory/discardable_shared_memory.h" 8 #include "base/memory/discardable_shared_memory.h"
9 #include "base/process/process_metrics.h" 9 #include "base/process/process_metrics.h"
10 #include "base/strings/string_number_conversions.h" 10 #include "base/strings/string_number_conversions.h"
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
44 ChildDiscardableSharedMemoryManager* manager_; 44 ChildDiscardableSharedMemoryManager* manager_;
45 scoped_ptr<DiscardableSharedMemoryHeap::Span> span_; 45 scoped_ptr<DiscardableSharedMemoryHeap::Span> span_;
46 46
47 DISALLOW_COPY_AND_ASSIGN(DiscardableMemoryShmemChunkImpl); 47 DISALLOW_COPY_AND_ASSIGN(DiscardableMemoryShmemChunkImpl);
48 }; 48 };
49 49
50 } // namespace 50 } // namespace
51 51
52 ChildDiscardableSharedMemoryManager::ChildDiscardableSharedMemoryManager( 52 ChildDiscardableSharedMemoryManager::ChildDiscardableSharedMemoryManager(
53 ThreadSafeSender* sender) 53 ThreadSafeSender* sender)
54 : heap_(base::GetPageSize()), sender_(sender), bytes_allocated_(0) { 54 : heap_(base::GetPageSize()), sender_(sender) {
55 } 55 }
56 56
57 ChildDiscardableSharedMemoryManager::~ChildDiscardableSharedMemoryManager() { 57 ChildDiscardableSharedMemoryManager::~ChildDiscardableSharedMemoryManager() {
58 if (bytes_allocated_) 58 DCHECK_EQ(heap_.GetSize(), heap_.GetFreeListSize());
59 BytesAllocatedChanged(0); 59 if (heap_.GetSize())
60 MemoryUsageChanged(0, 0);
60 } 61 }
61 62
62 scoped_ptr<base::DiscardableMemoryShmemChunk> 63 scoped_ptr<base::DiscardableMemoryShmemChunk>
63 ChildDiscardableSharedMemoryManager::AllocateLockedDiscardableMemory( 64 ChildDiscardableSharedMemoryManager::AllocateLockedDiscardableMemory(
64 size_t size) { 65 size_t size) {
65 base::AutoLock lock(lock_); 66 base::AutoLock lock(lock_);
66 67
67 DCHECK_NE(size, 0u); 68 DCHECK_NE(size, 0u);
68 69
69 // Round up to multiple of page size. 70 // Round up to multiple of page size.
70 size_t pages = (size + base::GetPageSize() - 1) / base::GetPageSize(); 71 size_t pages = (size + base::GetPageSize() - 1) / base::GetPageSize();
71 72
73 size_t heap_size_prior_to_releasing_purged_memory = heap_.GetSize();
72 for (;;) { 74 for (;;) {
73 // Search free list for available space. 75 // Search free list for available space.
74 scoped_ptr<DiscardableSharedMemoryHeap::Span> free_span = 76 scoped_ptr<DiscardableSharedMemoryHeap::Span> free_span =
75 heap_.SearchFreeList(pages); 77 heap_.SearchFreeList(pages);
76 if (!free_span.get()) 78 if (!free_span.get())
77 break; 79 break;
78 80
79 // Attempt to lock |free_span|. Delete span and search free list again 81 // Attempt to lock |free_span|. Delete span and search free list again
80 // if locking failed. 82 // if locking failed.
81 if (free_span->shared_memory()->Lock( 83 if (free_span->shared_memory()->Lock(
82 free_span->start() * base::GetPageSize() - 84 free_span->start() * base::GetPageSize() -
83 reinterpret_cast<size_t>(free_span->shared_memory()->memory()), 85 reinterpret_cast<size_t>(free_span->shared_memory()->memory()),
84 free_span->length() * base::GetPageSize()) == 86 free_span->length() * base::GetPageSize()) ==
85 base::DiscardableSharedMemory::FAILED) { 87 base::DiscardableSharedMemory::FAILED) {
86 DCHECK(!free_span->shared_memory()->IsMemoryResident()); 88 DCHECK(!free_span->shared_memory()->IsMemoryResident());
87 // We have to release free memory before |free_span| can be destroyed. 89 // We have to release purged memory before |free_span| can be destroyed.
88 size_t bytes_released = heap_.ReleaseFreeMemory(); 90 heap_.ReleasePurgedMemory();
89 DCHECK_NE(bytes_released, 0u);
90 DCHECK_LE(bytes_released, bytes_allocated_);
91 bytes_allocated_ -= bytes_released;
92 BytesAllocatedChanged(bytes_allocated_);
93 DCHECK(!free_span->shared_memory()); 91 DCHECK(!free_span->shared_memory());
94 continue; 92 continue;
95 } 93 }
96 94
95 // Memory usage is guaranteed to have changed after having removed
96 // at least one span from the free list.
97 MemoryUsageChanged(heap_.GetSize(), heap_.GetFreeListSize());
98
97 return make_scoped_ptr( 99 return make_scoped_ptr(
98 new DiscardableMemoryShmemChunkImpl(this, free_span.Pass())); 100 new DiscardableMemoryShmemChunkImpl(this, free_span.Pass()));
99 } 101 }
100 102
101 // Release free memory and free up the address space. Failing to do this 103 // Release purged memory to free up the address space before we attempt to
102 // can result in the child process running out of address space. 104 // allocate more memory.
103 size_t bytes_released = heap_.ReleaseFreeMemory(); 105 heap_.ReleasePurgedMemory();
104 if (bytes_released) { 106
105 DCHECK_LE(bytes_released, bytes_allocated_); 107 // Make sure crash keys are up to date in case allocation fails.
106 bytes_allocated_ -= bytes_released; 108 if (heap_.GetSize() != heap_size_prior_to_releasing_purged_memory)
107 BytesAllocatedChanged(bytes_allocated_); 109 MemoryUsageChanged(heap_.GetSize(), heap_.GetFreeListSize());
108 }
109 110
110 size_t pages_to_allocate = 111 size_t pages_to_allocate =
111 std::max(kAllocationSize / base::GetPageSize(), pages); 112 std::max(kAllocationSize / base::GetPageSize(), pages);
112 size_t allocation_size_in_bytes = pages_to_allocate * base::GetPageSize(); 113 size_t allocation_size_in_bytes = pages_to_allocate * base::GetPageSize();
113 114
114 // Ask parent process to allocate a new discardable shared memory segment. 115 // Ask parent process to allocate a new discardable shared memory segment.
115 scoped_ptr<base::DiscardableSharedMemory> shared_memory( 116 scoped_ptr<base::DiscardableSharedMemory> shared_memory(
116 AllocateLockedDiscardableSharedMemory(allocation_size_in_bytes)); 117 AllocateLockedDiscardableSharedMemory(allocation_size_in_bytes));
117 118
118 // Note: use mapped size rather than |allocation_size_in_bytes| as
119 // the latter only represent the amount of memory available for usage.
120 bytes_allocated_ += shared_memory->mapped_size();
121 BytesAllocatedChanged(bytes_allocated_);
122
123 // Create span for allocated memory. 119 // Create span for allocated memory.
124 scoped_ptr<DiscardableSharedMemoryHeap::Span> new_span( 120 scoped_ptr<DiscardableSharedMemoryHeap::Span> new_span(
125 heap_.Grow(shared_memory.Pass(), allocation_size_in_bytes)); 121 heap_.Grow(shared_memory.Pass()));
126 122
127 // Unlock and insert any left over memory into free list. 123 // Unlock and insert any left over memory into free list.
128 if (pages < pages_to_allocate) { 124 if (pages < pages_to_allocate) {
129 scoped_ptr<DiscardableSharedMemoryHeap::Span> leftover = 125 scoped_ptr<DiscardableSharedMemoryHeap::Span> leftover =
130 heap_.Split(new_span.get(), pages); 126 heap_.Split(new_span.get(), pages);
131 leftover->shared_memory()->Unlock( 127 leftover->shared_memory()->Unlock(
132 leftover->start() * base::GetPageSize() - 128 leftover->start() * base::GetPageSize() -
133 reinterpret_cast<size_t>(leftover->shared_memory()->memory()), 129 reinterpret_cast<size_t>(leftover->shared_memory()->memory()),
134 leftover->length() * base::GetPageSize()); 130 leftover->length() * base::GetPageSize());
135 heap_.MergeIntoFreeList(leftover.Pass()); 131 heap_.MergeIntoFreeList(leftover.Pass());
136 } 132 }
137 133
134 MemoryUsageChanged(heap_.GetSize(), heap_.GetFreeListSize());
135
138 return make_scoped_ptr( 136 return make_scoped_ptr(
139 new DiscardableMemoryShmemChunkImpl(this, new_span.Pass())); 137 new DiscardableMemoryShmemChunkImpl(this, new_span.Pass()));
140 } 138 }
141 139
142 void ChildDiscardableSharedMemoryManager::ReleaseFreeMemory() { 140 void ChildDiscardableSharedMemoryManager::ReleaseFreeMemory() {
143 base::AutoLock lock(lock_); 141 base::AutoLock lock(lock_);
144 142
145 size_t bytes_released = heap_.ReleaseFreeMemory(); 143 size_t heap_size_prior_to_releasing_memory = heap_.GetSize();
146 if (bytes_released) { 144
147 DCHECK_LE(bytes_released, bytes_allocated_); 145 // Release both purged and free memory.
148 bytes_allocated_ -= bytes_released; 146 heap_.ReleasePurgedMemory();
149 BytesAllocatedChanged(bytes_allocated_); 147 heap_.ReleaseFreeMemory();
150 } 148
149 if (heap_.GetSize() != heap_size_prior_to_releasing_memory)
150 MemoryUsageChanged(heap_.GetSize(), heap_.GetFreeListSize());
151 } 151 }
152 152
153 bool ChildDiscardableSharedMemoryManager::LockSpan( 153 bool ChildDiscardableSharedMemoryManager::LockSpan(
154 DiscardableSharedMemoryHeap::Span* span) { 154 DiscardableSharedMemoryHeap::Span* span) {
155 base::AutoLock lock(lock_); 155 base::AutoLock lock(lock_);
156 156
157 if (!span->shared_memory()) 157 if (!span->shared_memory())
158 return false; 158 return false;
159 159
160 size_t offset = span->start() * base::GetPageSize() - 160 size_t offset = span->start() * base::GetPageSize() -
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
194 // Delete span instead of merging it into free list if memory is gone. 194 // Delete span instead of merging it into free list if memory is gone.
195 if (!span->shared_memory()) 195 if (!span->shared_memory())
196 return; 196 return;
197 197
198 // Purge backing memory if span is greater than kAllocationSize. This will 198 // Purge backing memory if span is greater than kAllocationSize. This will
199 // prevent it from being reused and associated resources will be released. 199 // prevent it from being reused and associated resources will be released.
200 if (span->length() * base::GetPageSize() > kAllocationSize) 200 if (span->length() * base::GetPageSize() > kAllocationSize)
201 span->shared_memory()->Purge(base::Time::Now()); 201 span->shared_memory()->Purge(base::Time::Now());
202 202
203 heap_.MergeIntoFreeList(span.Pass()); 203 heap_.MergeIntoFreeList(span.Pass());
204
205 // Bytes of free memory changed.
206 MemoryUsageChanged(heap_.GetSize(), heap_.GetFreeListSize());
204 } 207 }
205 208
206 scoped_ptr<base::DiscardableSharedMemory> 209 scoped_ptr<base::DiscardableSharedMemory>
207 ChildDiscardableSharedMemoryManager::AllocateLockedDiscardableSharedMemory( 210 ChildDiscardableSharedMemoryManager::AllocateLockedDiscardableSharedMemory(
208 size_t size) { 211 size_t size) {
209 TRACE_EVENT1("renderer", 212 TRACE_EVENT1("renderer",
210 "ChildDiscardableSharedMemoryManager::" 213 "ChildDiscardableSharedMemoryManager::"
211 "AllocateLockedDiscardableSharedMemory", 214 "AllocateLockedDiscardableSharedMemory",
212 "size", 215 "size",
213 size); 216 size);
214 217
215 base::SharedMemoryHandle handle = base::SharedMemory::NULLHandle(); 218 base::SharedMemoryHandle handle = base::SharedMemory::NULLHandle();
216 sender_->Send( 219 sender_->Send(
217 new ChildProcessHostMsg_SyncAllocateLockedDiscardableSharedMemory( 220 new ChildProcessHostMsg_SyncAllocateLockedDiscardableSharedMemory(
218 size, &handle)); 221 size, &handle));
219 CHECK(base::SharedMemory::IsHandleValid(handle)); 222 CHECK(base::SharedMemory::IsHandleValid(handle));
220 scoped_ptr<base::DiscardableSharedMemory> memory( 223 scoped_ptr<base::DiscardableSharedMemory> memory(
221 new base::DiscardableSharedMemory(handle)); 224 new base::DiscardableSharedMemory(handle));
222 CHECK(memory->Map(size)); 225 CHECK(memory->Map(size));
223 return memory.Pass(); 226 return memory.Pass();
224 } 227 }
225 228
226 void ChildDiscardableSharedMemoryManager::BytesAllocatedChanged( 229 void ChildDiscardableSharedMemoryManager::MemoryUsageChanged(
227 size_t new_bytes_allocated) const { 230 size_t new_bytes_total,
228 TRACE_COUNTER_ID1("renderer", "DiscardableMemoryUsage", this, 231 size_t new_bytes_free) const {
229 new_bytes_allocated); 232 TRACE_COUNTER2("renderer", "DiscardableMemoryUsage", "allocated",
233 new_bytes_total - new_bytes_free, "free", new_bytes_free);
230 234
231 static const char kDiscardableMemoryUsageKey[] = "dm-usage"; 235 static const char kDiscardableMemoryUsageKey[] = "dm-usage";
232 base::debug::SetCrashKeyValue(kDiscardableMemoryUsageKey, 236 base::debug::SetCrashKeyValue(kDiscardableMemoryUsageKey,
233 base::Uint64ToString(new_bytes_allocated)); 237 base::Uint64ToString(new_bytes_total));
238
239 static const char kDiscardableMemoryUsageFreeKey[] = "dm-usage-free";
240 base::debug::SetCrashKeyValue(kDiscardableMemoryUsageFreeKey,
241 base::Uint64ToString(new_bytes_free));
234 } 242 }
235 243
236 } // namespace content 244 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698