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

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

Powered by Google App Engine
This is Rietveld 408576698