1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "rosalloc.h" 18 19 #include <list> 20 #include <map> 21 #include <sstream> 22 #include <vector> 23 24 #include "android-base/stringprintf.h" 25 26 #include "base/logging.h" // For VLOG 27 #include "base/memory_tool.h" 28 #include "base/mutex-inl.h" 29 #include "gc/space/memory_tool_settings.h" 30 #include "mem_map.h" 31 #include "mirror/class-inl.h" 32 #include "mirror/object-inl.h" 33 #include "mirror/object.h" 34 #include "thread-current-inl.h" 35 #include "thread_list.h" 36 37 namespace art { 38 namespace gc { 39 namespace allocator { 40 41 using android::base::StringPrintf; 42 43 static constexpr bool kUsePrefetchDuringAllocRun = false; 44 static constexpr bool kPrefetchNewRunDataByZeroing = false; 45 static constexpr size_t kPrefetchStride = 64; 46 47 size_t RosAlloc::bracketSizes[kNumOfSizeBrackets]; 48 size_t RosAlloc::numOfPages[kNumOfSizeBrackets]; 49 size_t RosAlloc::numOfSlots[kNumOfSizeBrackets]; 50 size_t RosAlloc::headerSizes[kNumOfSizeBrackets]; 51 bool RosAlloc::initialized_ = false; 52 size_t RosAlloc::dedicated_full_run_storage_[kPageSize / sizeof(size_t)] = { 0 }; 53 RosAlloc::Run* RosAlloc::dedicated_full_run_ = 54 reinterpret_cast<RosAlloc::Run*>(dedicated_full_run_storage_); 55 56 RosAlloc::RosAlloc(void* base, size_t capacity, size_t max_capacity, 57 PageReleaseMode page_release_mode, bool running_on_memory_tool, 58 size_t page_release_size_threshold) 59 : base_(reinterpret_cast<uint8_t*>(base)), footprint_(capacity), 60 capacity_(capacity), max_capacity_(max_capacity), 61 lock_("rosalloc global lock", kRosAllocGlobalLock), 62 bulk_free_lock_("rosalloc bulk free lock", kRosAllocBulkFreeLock), 63 page_release_mode_(page_release_mode), 64 page_release_size_threshold_(page_release_size_threshold), 65 is_running_on_memory_tool_(running_on_memory_tool) { 66 DCHECK_ALIGNED(base, kPageSize); 67 DCHECK_EQ(RoundUp(capacity, kPageSize), capacity); 68 DCHECK_EQ(RoundUp(max_capacity, kPageSize), max_capacity); 69 CHECK_LE(capacity, max_capacity); 70 CHECK_ALIGNED(page_release_size_threshold_, kPageSize); 71 // Zero the memory explicitly (don't rely on that the mem map is zero-initialized). 72 if (!kMadviseZeroes) { 73 memset(base_, 0, max_capacity); 74 } 75 CHECK_EQ(madvise(base_, max_capacity, MADV_DONTNEED), 0); 76 if (!initialized_) { 77 Initialize(); 78 } 79 VLOG(heap) << "RosAlloc base=" 80 << std::hex << (intptr_t)base_ << ", end=" 81 << std::hex << (intptr_t)(base_ + capacity_) 82 << ", capacity=" << std::dec << capacity_ 83 << ", max_capacity=" << std::dec << max_capacity_; 84 for (size_t i = 0; i < kNumOfSizeBrackets; i++) { 85 size_bracket_lock_names_[i] = 86 StringPrintf("an rosalloc size bracket %d lock", static_cast<int>(i)); 87 size_bracket_locks_[i] = new Mutex(size_bracket_lock_names_[i].c_str(), kRosAllocBracketLock); 88 current_runs_[i] = dedicated_full_run_; 89 } 90 DCHECK_EQ(footprint_, capacity_); 91 size_t num_of_pages = footprint_ / kPageSize; 92 size_t max_num_of_pages = max_capacity_ / kPageSize; 93 std::string error_msg; 94 page_map_mem_map_.reset(MemMap::MapAnonymous("rosalloc page map", nullptr, 95 RoundUp(max_num_of_pages, kPageSize), 96 PROT_READ | PROT_WRITE, false, false, &error_msg)); 97 CHECK(page_map_mem_map_.get() != nullptr) << "Couldn't allocate the page map : " << error_msg; 98 page_map_ = page_map_mem_map_->Begin(); 99 page_map_size_ = num_of_pages; 100 max_page_map_size_ = max_num_of_pages; 101 free_page_run_size_map_.resize(num_of_pages); 102 FreePageRun* free_pages = reinterpret_cast<FreePageRun*>(base_); 103 if (kIsDebugBuild) { 104 free_pages->magic_num_ = kMagicNumFree; 105 } 106 free_pages->SetByteSize(this, capacity_); 107 DCHECK_EQ(capacity_ % kPageSize, static_cast<size_t>(0)); 108 DCHECK(free_pages->IsFree()); 109 free_pages->ReleasePages(this); 110 DCHECK(free_pages->IsFree()); 111 free_page_runs_.insert(free_pages); 112 if (kTraceRosAlloc) { 113 LOG(INFO) << "RosAlloc::RosAlloc() : Inserted run 0x" << std::hex 114 << reinterpret_cast<intptr_t>(free_pages) 115 << " into free_page_runs_"; 116 } 117 } 118 119 RosAlloc::~RosAlloc() { 120 for (size_t i = 0; i < kNumOfSizeBrackets; i++) { 121 delete size_bracket_locks_[i]; 122 } 123 if (is_running_on_memory_tool_) { 124 MEMORY_TOOL_MAKE_DEFINED(base_, capacity_); 125 } 126 } 127 128 void* RosAlloc::AllocPages(Thread* self, size_t num_pages, uint8_t page_map_type) { 129 lock_.AssertHeld(self); 130 DCHECK(page_map_type == kPageMapRun || page_map_type == kPageMapLargeObject); 131 FreePageRun* res = nullptr; 132 const size_t req_byte_size = num_pages * kPageSize; 133 // Find the lowest address free page run that's large enough. 134 for (auto it = free_page_runs_.begin(); it != free_page_runs_.end(); ) { 135 FreePageRun* fpr = *it; 136 DCHECK(fpr->IsFree()); 137 size_t fpr_byte_size = fpr->ByteSize(this); 138 DCHECK_EQ(fpr_byte_size % kPageSize, static_cast<size_t>(0)); 139 if (req_byte_size <= fpr_byte_size) { 140 // Found one. 141 it = free_page_runs_.erase(it); 142 if (kTraceRosAlloc) { 143 LOG(INFO) << "RosAlloc::AllocPages() : Erased run 0x" 144 << std::hex << reinterpret_cast<intptr_t>(fpr) 145 << " from free_page_runs_"; 146 } 147 if (req_byte_size < fpr_byte_size) { 148 // Split. 149 FreePageRun* remainder = 150 reinterpret_cast<FreePageRun*>(reinterpret_cast<uint8_t*>(fpr) + req_byte_size); 151 if (kIsDebugBuild) { 152 remainder->magic_num_ = kMagicNumFree; 153 } 154 remainder->SetByteSize(this, fpr_byte_size - req_byte_size); 155 DCHECK_EQ(remainder->ByteSize(this) % kPageSize, static_cast<size_t>(0)); 156 // Don't need to call madvise on remainder here. 157 free_page_runs_.insert(remainder); 158 if (kTraceRosAlloc) { 159 LOG(INFO) << "RosAlloc::AllocPages() : Inserted run 0x" << std::hex 160 << reinterpret_cast<intptr_t>(remainder) 161 << " into free_page_runs_"; 162 } 163 fpr->SetByteSize(this, req_byte_size); 164 DCHECK_EQ(fpr->ByteSize(this) % kPageSize, static_cast<size_t>(0)); 165 } 166 res = fpr; 167 break; 168 } else { 169 ++it; 170 } 171 } 172 173 // Failed to allocate pages. Grow the footprint, if possible. 174 if (UNLIKELY(res == nullptr && capacity_ > footprint_)) { 175 FreePageRun* last_free_page_run = nullptr; 176 size_t last_free_page_run_size; 177 auto it = free_page_runs_.rbegin(); 178 if (it != free_page_runs_.rend() && (last_free_page_run = *it)->End(this) == base_ + footprint_) { 179 // There is a free page run at the end. 180 DCHECK(last_free_page_run->IsFree()); 181 DCHECK(IsFreePage(ToPageMapIndex(last_free_page_run))); 182 last_free_page_run_size = last_free_page_run->ByteSize(this); 183 } else { 184 // There is no free page run at the end. 185 last_free_page_run_size = 0; 186 } 187 DCHECK_LT(last_free_page_run_size, req_byte_size); 188 if (capacity_ - footprint_ + last_free_page_run_size >= req_byte_size) { 189 // If we grow the heap, we can allocate it. 190 size_t increment = std::min(std::max(2 * MB, req_byte_size - last_free_page_run_size), 191 capacity_ - footprint_); 192 DCHECK_EQ(increment % kPageSize, static_cast<size_t>(0)); 193 size_t new_footprint = footprint_ + increment; 194 size_t new_num_of_pages = new_footprint / kPageSize; 195 DCHECK_LT(page_map_size_, new_num_of_pages); 196 DCHECK_LT(free_page_run_size_map_.size(), new_num_of_pages); 197 page_map_size_ = new_num_of_pages; 198 DCHECK_LE(page_map_size_, max_page_map_size_); 199 free_page_run_size_map_.resize(new_num_of_pages); 200 ArtRosAllocMoreCore(this, increment); 201 if (last_free_page_run_size > 0) { 202 // There was a free page run at the end. Expand its size. 203 DCHECK_EQ(last_free_page_run_size, last_free_page_run->ByteSize(this)); 204 last_free_page_run->SetByteSize(this, last_free_page_run_size + increment); 205 DCHECK_EQ(last_free_page_run->ByteSize(this) % kPageSize, static_cast<size_t>(0)); 206 DCHECK_EQ(last_free_page_run->End(this), base_ + new_footprint); 207 } else { 208 // Otherwise, insert a new free page run at the end. 209 FreePageRun* new_free_page_run = reinterpret_cast<FreePageRun*>(base_ + footprint_); 210 if (kIsDebugBuild) { 211 new_free_page_run->magic_num_ = kMagicNumFree; 212 } 213 new_free_page_run->SetByteSize(this, increment); 214 DCHECK_EQ(new_free_page_run->ByteSize(this) % kPageSize, static_cast<size_t>(0)); 215 free_page_runs_.insert(new_free_page_run); 216 DCHECK_EQ(*free_page_runs_.rbegin(), new_free_page_run); 217 if (kTraceRosAlloc) { 218 LOG(INFO) << "RosAlloc::AlloPages() : Grew the heap by inserting run 0x" 219 << std::hex << reinterpret_cast<intptr_t>(new_free_page_run) 220 << " into free_page_runs_"; 221 } 222 } 223 DCHECK_LE(footprint_ + increment, capacity_); 224 if (kTraceRosAlloc) { 225 LOG(INFO) << "RosAlloc::AllocPages() : increased the footprint from " 226 << footprint_ << " to " << new_footprint; 227 } 228 footprint_ = new_footprint; 229 230 // And retry the last free page run. 231 it = free_page_runs_.rbegin(); 232 DCHECK(it != free_page_runs_.rend()); 233 FreePageRun* fpr = *it; 234 if (kIsDebugBuild && last_free_page_run_size > 0) { 235 DCHECK(last_free_page_run != nullptr); 236 DCHECK_EQ(last_free_page_run, fpr); 237 } 238 size_t fpr_byte_size = fpr->ByteSize(this); 239 DCHECK_EQ(fpr_byte_size % kPageSize, static_cast<size_t>(0)); 240 DCHECK_LE(req_byte_size, fpr_byte_size); 241 free_page_runs_.erase(fpr); 242 if (kTraceRosAlloc) { 243 LOG(INFO) << "RosAlloc::AllocPages() : Erased run 0x" << std::hex << reinterpret_cast<intptr_t>(fpr) 244 << " from free_page_runs_"; 245 } 246 if (req_byte_size < fpr_byte_size) { 247 // Split if there's a remainder. 248 FreePageRun* remainder = reinterpret_cast<FreePageRun*>(reinterpret_cast<uint8_t*>(fpr) + req_byte_size); 249 if (kIsDebugBuild) { 250 remainder->magic_num_ = kMagicNumFree; 251 } 252 remainder->SetByteSize(this, fpr_byte_size - req_byte_size); 253 DCHECK_EQ(remainder->ByteSize(this) % kPageSize, static_cast<size_t>(0)); 254 free_page_runs_.insert(remainder); 255 if (kTraceRosAlloc) { 256 LOG(INFO) << "RosAlloc::AllocPages() : Inserted run 0x" << std::hex 257 << reinterpret_cast<intptr_t>(remainder) 258 << " into free_page_runs_"; 259 } 260 fpr->SetByteSize(this, req_byte_size); 261 DCHECK_EQ(fpr->ByteSize(this) % kPageSize, static_cast<size_t>(0)); 262 } 263 res = fpr; 264 } 265 } 266 if (LIKELY(res != nullptr)) { 267 // Update the page map. 268 size_t page_map_idx = ToPageMapIndex(res); 269 for (size_t i = 0; i < num_pages; i++) { 270 DCHECK(IsFreePage(page_map_idx + i)); 271 } 272 switch (page_map_type) { 273 case kPageMapRun: 274 page_map_[page_map_idx] = kPageMapRun; 275 for (size_t i = 1; i < num_pages; i++) { 276 page_map_[page_map_idx + i] = kPageMapRunPart; 277 } 278 break; 279 case kPageMapLargeObject: 280 page_map_[page_map_idx] = kPageMapLargeObject; 281 for (size_t i = 1; i < num_pages; i++) { 282 page_map_[page_map_idx + i] = kPageMapLargeObjectPart; 283 } 284 break; 285 default: 286 LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(page_map_type); 287 break; 288 } 289 if (kIsDebugBuild) { 290 // Clear the first page since it is not madvised due to the magic number. 291 memset(res, 0, kPageSize); 292 } 293 if (kTraceRosAlloc) { 294 LOG(INFO) << "RosAlloc::AllocPages() : 0x" << std::hex << reinterpret_cast<intptr_t>(res) 295 << "-0x" << (reinterpret_cast<intptr_t>(res) + num_pages * kPageSize) 296 << "(" << std::dec << (num_pages * kPageSize) << ")"; 297 } 298 return res; 299 } 300 301 // Fail. 302 if (kTraceRosAlloc) { 303 LOG(INFO) << "RosAlloc::AllocPages() : nullptr"; 304 } 305 return nullptr; 306 } 307 308 size_t RosAlloc::FreePages(Thread* self, void* ptr, bool already_zero) { 309 lock_.AssertHeld(self); 310 size_t pm_idx = ToPageMapIndex(ptr); 311 DCHECK_LT(pm_idx, page_map_size_); 312 uint8_t pm_type = page_map_[pm_idx]; 313 DCHECK(pm_type == kPageMapRun || pm_type == kPageMapLargeObject); 314 uint8_t pm_part_type; 315 switch (pm_type) { 316 case kPageMapRun: 317 pm_part_type = kPageMapRunPart; 318 break; 319 case kPageMapLargeObject: 320 pm_part_type = kPageMapLargeObjectPart; 321 break; 322 default: 323 LOG(FATAL) << "Unreachable - " << __PRETTY_FUNCTION__ << " : " << "pm_idx=" << pm_idx << ", pm_type=" 324 << static_cast<int>(pm_type) << ", ptr=" << std::hex 325 << reinterpret_cast<intptr_t>(ptr); 326 return 0; 327 } 328 // Update the page map and count the number of pages. 329 size_t num_pages = 1; 330 page_map_[pm_idx] = kPageMapEmpty; 331 size_t idx = pm_idx + 1; 332 size_t end = page_map_size_; 333 while (idx < end && page_map_[idx] == pm_part_type) { 334 page_map_[idx] = kPageMapEmpty; 335 num_pages++; 336 idx++; 337 } 338 const size_t byte_size = num_pages * kPageSize; 339 if (already_zero) { 340 if (ShouldCheckZeroMemory()) { 341 const uintptr_t* word_ptr = reinterpret_cast<uintptr_t*>(ptr); 342 for (size_t i = 0; i < byte_size / sizeof(uintptr_t); ++i) { 343 CHECK_EQ(word_ptr[i], 0U) << "words don't match at index " << i; 344 } 345 } 346 } else if (!DoesReleaseAllPages()) { 347 memset(ptr, 0, byte_size); 348 } 349 350 if (kTraceRosAlloc) { 351 LOG(INFO) << __PRETTY_FUNCTION__ << " : 0x" << std::hex << reinterpret_cast<intptr_t>(ptr) 352 << "-0x" << (reinterpret_cast<intptr_t>(ptr) + byte_size) 353 << "(" << std::dec << (num_pages * kPageSize) << ")"; 354 } 355 356 // Turn it into a free run. 357 FreePageRun* fpr = reinterpret_cast<FreePageRun*>(ptr); 358 if (kIsDebugBuild) { 359 fpr->magic_num_ = kMagicNumFree; 360 } 361 fpr->SetByteSize(this, byte_size); 362 DCHECK_ALIGNED(fpr->ByteSize(this), kPageSize); 363 364 DCHECK(free_page_runs_.find(fpr) == free_page_runs_.end()); 365 if (!free_page_runs_.empty()) { 366 // Try to coalesce in the higher address direction. 367 if (kTraceRosAlloc) { 368 LOG(INFO) << __PRETTY_FUNCTION__ << "RosAlloc::FreePages() : trying to coalesce a free page run 0x" 369 << std::hex << reinterpret_cast<uintptr_t>(fpr) << " [" << std::dec << pm_idx << "] -0x" 370 << std::hex << reinterpret_cast<uintptr_t>(fpr->End(this)) << " [" << std::dec 371 << (fpr->End(this) == End() ? page_map_size_ : ToPageMapIndex(fpr->End(this))) << "]"; 372 } 373 for (auto it = free_page_runs_.upper_bound(fpr); it != free_page_runs_.end(); ) { 374 FreePageRun* h = *it; 375 DCHECK_EQ(h->ByteSize(this) % kPageSize, static_cast<size_t>(0)); 376 if (kTraceRosAlloc) { 377 LOG(INFO) << "RosAlloc::FreePages() : trying to coalesce with a higher free page run 0x" 378 << std::hex << reinterpret_cast<uintptr_t>(h) << " [" << std::dec << ToPageMapIndex(h) << "] -0x" 379 << std::hex << reinterpret_cast<uintptr_t>(h->End(this)) << " [" << std::dec 380 << (h->End(this) == End() ? page_map_size_ : ToPageMapIndex(h->End(this))) << "]"; 381 } 382 if (fpr->End(this) == h->Begin()) { 383 if (kTraceRosAlloc) { 384 LOG(INFO) << "Success"; 385 } 386 // Clear magic num since this is no longer the start of a free page run. 387 if (kIsDebugBuild) { 388 h->magic_num_ = 0; 389 } 390 it = free_page_runs_.erase(it); 391 if (kTraceRosAlloc) { 392 LOG(INFO) << "RosAlloc::FreePages() : (coalesce) Erased run 0x" << std::hex 393 << reinterpret_cast<intptr_t>(h) 394 << " from free_page_runs_"; 395 } 396 fpr->SetByteSize(this, fpr->ByteSize(this) + h->ByteSize(this)); 397 DCHECK_EQ(fpr->ByteSize(this) % kPageSize, static_cast<size_t>(0)); 398 } else { 399 // Not adjacent. Stop. 400 if (kTraceRosAlloc) { 401 LOG(INFO) << "Fail"; 402 } 403 break; 404 } 405 } 406 // Try to coalesce in the lower address direction. 407 for (auto it = free_page_runs_.upper_bound(fpr); it != free_page_runs_.begin(); ) { 408 --it; 409 410 FreePageRun* l = *it; 411 DCHECK_EQ(l->ByteSize(this) % kPageSize, static_cast<size_t>(0)); 412 if (kTraceRosAlloc) { 413 LOG(INFO) << "RosAlloc::FreePages() : trying to coalesce with a lower free page run 0x" 414 << std::hex << reinterpret_cast<uintptr_t>(l) << " [" << std::dec << ToPageMapIndex(l) << "] -0x" 415 << std::hex << reinterpret_cast<uintptr_t>(l->End(this)) << " [" << std::dec 416 << (l->End(this) == End() ? page_map_size_ : ToPageMapIndex(l->End(this))) << "]"; 417 } 418 if (l->End(this) == fpr->Begin()) { 419 if (kTraceRosAlloc) { 420 LOG(INFO) << "Success"; 421 } 422 it = free_page_runs_.erase(it); 423 if (kTraceRosAlloc) { 424 LOG(INFO) << "RosAlloc::FreePages() : (coalesce) Erased run 0x" << std::hex 425 << reinterpret_cast<intptr_t>(l) 426 << " from free_page_runs_"; 427 } 428 l->SetByteSize(this, l->ByteSize(this) + fpr->ByteSize(this)); 429 DCHECK_EQ(l->ByteSize(this) % kPageSize, static_cast<size_t>(0)); 430 // Clear magic num since this is no longer the start of a free page run. 431 if (kIsDebugBuild) { 432 fpr->magic_num_ = 0; 433 } 434 fpr = l; 435 } else { 436 // Not adjacent. Stop. 437 if (kTraceRosAlloc) { 438 LOG(INFO) << "Fail"; 439 } 440 break; 441 } 442 } 443 } 444 445 // Insert it. 446 DCHECK_EQ(fpr->ByteSize(this) % kPageSize, static_cast<size_t>(0)); 447 DCHECK(free_page_runs_.find(fpr) == free_page_runs_.end()); 448 DCHECK(fpr->IsFree()); 449 fpr->ReleasePages(this); 450 DCHECK(fpr->IsFree()); 451 free_page_runs_.insert(fpr); 452 DCHECK(free_page_runs_.find(fpr) != free_page_runs_.end()); 453 if (kTraceRosAlloc) { 454 LOG(INFO) << "RosAlloc::FreePages() : Inserted run 0x" << std::hex << reinterpret_cast<intptr_t>(fpr) 455 << " into free_page_runs_"; 456 } 457 return byte_size; 458 } 459 460 void* RosAlloc::AllocLargeObject(Thread* self, size_t size, size_t* bytes_allocated, 461 size_t* usable_size, size_t* bytes_tl_bulk_allocated) { 462 DCHECK(bytes_allocated != nullptr); 463 DCHECK(usable_size != nullptr); 464 DCHECK_GT(size, kLargeSizeThreshold); 465 size_t num_pages = RoundUp(size, kPageSize) / kPageSize; 466 void* r; 467 { 468 MutexLock mu(self, lock_); 469 r = AllocPages(self, num_pages, kPageMapLargeObject); 470 } 471 if (UNLIKELY(r == nullptr)) { 472 if (kTraceRosAlloc) { 473 LOG(INFO) << "RosAlloc::AllocLargeObject() : nullptr"; 474 } 475 return nullptr; 476 } 477 const size_t total_bytes = num_pages * kPageSize; 478 *bytes_allocated = total_bytes; 479 *usable_size = total_bytes; 480 *bytes_tl_bulk_allocated = total_bytes; 481 if (kTraceRosAlloc) { 482 LOG(INFO) << "RosAlloc::AllocLargeObject() : 0x" << std::hex << reinterpret_cast<intptr_t>(r) 483 << "-0x" << (reinterpret_cast<intptr_t>(r) + num_pages * kPageSize) 484 << "(" << std::dec << (num_pages * kPageSize) << ")"; 485 } 486 // Check if the returned memory is really all zero. 487 if (ShouldCheckZeroMemory()) { 488 CHECK_EQ(total_bytes % sizeof(uintptr_t), 0U); 489 const uintptr_t* words = reinterpret_cast<uintptr_t*>(r); 490 for (size_t i = 0; i < total_bytes / sizeof(uintptr_t); ++i) { 491 CHECK_EQ(words[i], 0U); 492 } 493 } 494 return r; 495 } 496 497 size_t RosAlloc::FreeInternal(Thread* self, void* ptr) { 498 DCHECK_LE(base_, ptr); 499 DCHECK_LT(ptr, base_ + footprint_); 500 size_t pm_idx = RoundDownToPageMapIndex(ptr); 501 Run* run = nullptr; 502 { 503 MutexLock mu(self, lock_); 504 DCHECK_LT(pm_idx, page_map_size_); 505 uint8_t page_map_entry = page_map_[pm_idx]; 506 if (kTraceRosAlloc) { 507 LOG(INFO) << "RosAlloc::FreeInternal() : " << std::hex << ptr << ", pm_idx=" << std::dec << pm_idx 508 << ", page_map_entry=" << static_cast<int>(page_map_entry); 509 } 510 switch (page_map_[pm_idx]) { 511 case kPageMapLargeObject: 512 return FreePages(self, ptr, false); 513 case kPageMapLargeObjectPart: 514 LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(page_map_[pm_idx]); 515 return 0; 516 case kPageMapRunPart: { 517 // Find the beginning of the run. 518 do { 519 --pm_idx; 520 DCHECK_LT(pm_idx, capacity_ / kPageSize); 521 } while (page_map_[pm_idx] != kPageMapRun); 522 FALLTHROUGH_INTENDED; 523 case kPageMapRun: 524 run = reinterpret_cast<Run*>(base_ + pm_idx * kPageSize); 525 DCHECK_EQ(run->magic_num_, kMagicNum); 526 break; 527 case kPageMapReleased: 528 case kPageMapEmpty: 529 LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(page_map_[pm_idx]); 530 return 0; 531 } 532 default: 533 LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(page_map_[pm_idx]); 534 return 0; 535 } 536 } 537 DCHECK(run != nullptr); 538 return FreeFromRun(self, ptr, run); 539 } 540 541 size_t RosAlloc::Free(Thread* self, void* ptr) { 542 ReaderMutexLock rmu(self, bulk_free_lock_); 543 return FreeInternal(self, ptr); 544 } 545 546 RosAlloc::Run* RosAlloc::AllocRun(Thread* self, size_t idx) { 547 RosAlloc::Run* new_run = nullptr; 548 { 549 MutexLock mu(self, lock_); 550 new_run = reinterpret_cast<Run*>(AllocPages(self, numOfPages[idx], kPageMapRun)); 551 } 552 if (LIKELY(new_run != nullptr)) { 553 if (kIsDebugBuild) { 554 new_run->magic_num_ = kMagicNum; 555 } 556 new_run->size_bracket_idx_ = idx; 557 DCHECK(!new_run->IsThreadLocal()); 558 DCHECK(!new_run->to_be_bulk_freed_); 559 if (kUsePrefetchDuringAllocRun && idx < kNumThreadLocalSizeBrackets) { 560 // Take ownership of the cache lines if we are likely to be thread local run. 561 if (kPrefetchNewRunDataByZeroing) { 562 // Zeroing the data is sometimes faster than prefetching but it increases memory usage 563 // since we end up dirtying zero pages which may have been madvised. 564 new_run->ZeroData(); 565 } else { 566 const size_t num_of_slots = numOfSlots[idx]; 567 const size_t bracket_size = bracketSizes[idx]; 568 const size_t num_of_bytes = num_of_slots * bracket_size; 569 uint8_t* begin = reinterpret_cast<uint8_t*>(new_run) + headerSizes[idx]; 570 for (size_t i = 0; i < num_of_bytes; i += kPrefetchStride) { 571 __builtin_prefetch(begin + i); 572 } 573 } 574 } 575 new_run->InitFreeList(); 576 } 577 return new_run; 578 } 579 580 RosAlloc::Run* RosAlloc::RefillRun(Thread* self, size_t idx) { 581 // Get the lowest address non-full run from the binary tree. 582 auto* const bt = &non_full_runs_[idx]; 583 if (!bt->empty()) { 584 // If there's one, use it as the current run. 585 auto it = bt->begin(); 586 Run* non_full_run = *it; 587 DCHECK(non_full_run != nullptr); 588 DCHECK(!non_full_run->IsThreadLocal()); 589 bt->erase(it); 590 return non_full_run; 591 } 592 // If there's none, allocate a new run and use it as the current run. 593 return AllocRun(self, idx); 594 } 595 596 inline void* RosAlloc::AllocFromCurrentRunUnlocked(Thread* self, size_t idx) { 597 Run* current_run = current_runs_[idx]; 598 DCHECK(current_run != nullptr); 599 void* slot_addr = current_run->AllocSlot(); 600 if (UNLIKELY(slot_addr == nullptr)) { 601 // The current run got full. Try to refill it. 602 DCHECK(current_run->IsFull()); 603 if (kIsDebugBuild && current_run != dedicated_full_run_) { 604 full_runs_[idx].insert(current_run); 605 if (kTraceRosAlloc) { 606 LOG(INFO) << __PRETTY_FUNCTION__ << " : Inserted run 0x" << std::hex 607 << reinterpret_cast<intptr_t>(current_run) 608 << " into full_runs_[" << std::dec << idx << "]"; 609 } 610 DCHECK(non_full_runs_[idx].find(current_run) == non_full_runs_[idx].end()); 611 DCHECK(full_runs_[idx].find(current_run) != full_runs_[idx].end()); 612 } 613 current_run = RefillRun(self, idx); 614 if (UNLIKELY(current_run == nullptr)) { 615 // Failed to allocate a new run, make sure that it is the dedicated full run. 616 current_runs_[idx] = dedicated_full_run_; 617 return nullptr; 618 } 619 DCHECK(current_run != nullptr); 620 DCHECK(non_full_runs_[idx].find(current_run) == non_full_runs_[idx].end()); 621 DCHECK(full_runs_[idx].find(current_run) == full_runs_[idx].end()); 622 current_run->SetIsThreadLocal(false); 623 current_runs_[idx] = current_run; 624 DCHECK(!current_run->IsFull()); 625 slot_addr = current_run->AllocSlot(); 626 // Must succeed now with a new run. 627 DCHECK(slot_addr != nullptr); 628 } 629 return slot_addr; 630 } 631 632 void* RosAlloc::AllocFromRunThreadUnsafe(Thread* self, size_t size, size_t* bytes_allocated, 633 size_t* usable_size, 634 size_t* bytes_tl_bulk_allocated) { 635 DCHECK(bytes_allocated != nullptr); 636 DCHECK(usable_size != nullptr); 637 DCHECK(bytes_tl_bulk_allocated != nullptr); 638 DCHECK_LE(size, kLargeSizeThreshold); 639 size_t bracket_size; 640 size_t idx = SizeToIndexAndBracketSize(size, &bracket_size); 641 Locks::mutator_lock_->AssertExclusiveHeld(self); 642 void* slot_addr = AllocFromCurrentRunUnlocked(self, idx); 643 if (LIKELY(slot_addr != nullptr)) { 644 *bytes_allocated = bracket_size; 645 *usable_size = bracket_size; 646 *bytes_tl_bulk_allocated = bracket_size; 647 } 648 // Caller verifies that it is all 0. 649 return slot_addr; 650 } 651 652 void* RosAlloc::AllocFromRun(Thread* self, size_t size, size_t* bytes_allocated, 653 size_t* usable_size, size_t* bytes_tl_bulk_allocated) { 654 DCHECK(bytes_allocated != nullptr); 655 DCHECK(usable_size != nullptr); 656 DCHECK(bytes_tl_bulk_allocated != nullptr); 657 DCHECK_LE(size, kLargeSizeThreshold); 658 size_t bracket_size; 659 size_t idx = SizeToIndexAndBracketSize(size, &bracket_size); 660 void* slot_addr; 661 if (LIKELY(idx < kNumThreadLocalSizeBrackets)) { 662 // Use a thread-local run. 663 Run* thread_local_run = reinterpret_cast<Run*>(self->GetRosAllocRun(idx)); 664 // Allow invalid since this will always fail the allocation. 665 if (kIsDebugBuild) { 666 // Need the lock to prevent race conditions. 667 MutexLock mu(self, *size_bracket_locks_[idx]); 668 CHECK(non_full_runs_[idx].find(thread_local_run) == non_full_runs_[idx].end()); 669 CHECK(full_runs_[idx].find(thread_local_run) == full_runs_[idx].end()); 670 } 671 DCHECK(thread_local_run != nullptr); 672 DCHECK(thread_local_run->IsThreadLocal() || thread_local_run == dedicated_full_run_); 673 slot_addr = thread_local_run->AllocSlot(); 674 // The allocation must fail if the run is invalid. 675 DCHECK(thread_local_run != dedicated_full_run_ || slot_addr == nullptr) 676 << "allocated from an invalid run"; 677 if (UNLIKELY(slot_addr == nullptr)) { 678 // The run got full. Try to free slots. 679 DCHECK(thread_local_run->IsFull()); 680 MutexLock mu(self, *size_bracket_locks_[idx]); 681 bool is_all_free_after_merge; 682 // This is safe to do for the dedicated_full_run_ since the bitmaps are empty. 683 if (thread_local_run->MergeThreadLocalFreeListToFreeList(&is_all_free_after_merge)) { 684 DCHECK_NE(thread_local_run, dedicated_full_run_); 685 // Some slot got freed. Keep it. 686 DCHECK(!thread_local_run->IsFull()); 687 DCHECK_EQ(is_all_free_after_merge, thread_local_run->IsAllFree()); 688 } else { 689 // No slots got freed. Try to refill the thread-local run. 690 DCHECK(thread_local_run->IsFull()); 691 if (thread_local_run != dedicated_full_run_) { 692 thread_local_run->SetIsThreadLocal(false); 693 if (kIsDebugBuild) { 694 full_runs_[idx].insert(thread_local_run); 695 if (kTraceRosAlloc) { 696 LOG(INFO) << "RosAlloc::AllocFromRun() : Inserted run 0x" << std::hex 697 << reinterpret_cast<intptr_t>(thread_local_run) 698 << " into full_runs_[" << std::dec << idx << "]"; 699 } 700 } 701 DCHECK(non_full_runs_[idx].find(thread_local_run) == non_full_runs_[idx].end()); 702 DCHECK(full_runs_[idx].find(thread_local_run) != full_runs_[idx].end()); 703 } 704 705 thread_local_run = RefillRun(self, idx); 706 if (UNLIKELY(thread_local_run == nullptr)) { 707 self->SetRosAllocRun(idx, dedicated_full_run_); 708 return nullptr; 709 } 710 DCHECK(non_full_runs_[idx].find(thread_local_run) == non_full_runs_[idx].end()); 711 DCHECK(full_runs_[idx].find(thread_local_run) == full_runs_[idx].end()); 712 thread_local_run->SetIsThreadLocal(true); 713 self->SetRosAllocRun(idx, thread_local_run); 714 DCHECK(!thread_local_run->IsFull()); 715 } 716 DCHECK(thread_local_run != nullptr); 717 DCHECK(!thread_local_run->IsFull()); 718 DCHECK(thread_local_run->IsThreadLocal()); 719 // Account for all the free slots in the new or refreshed thread local run. 720 *bytes_tl_bulk_allocated = thread_local_run->NumberOfFreeSlots() * bracket_size; 721 slot_addr = thread_local_run->AllocSlot(); 722 // Must succeed now with a new run. 723 DCHECK(slot_addr != nullptr); 724 } else { 725 // The slot is already counted. Leave it as is. 726 *bytes_tl_bulk_allocated = 0; 727 } 728 DCHECK(slot_addr != nullptr); 729 if (kTraceRosAlloc) { 730 LOG(INFO) << "RosAlloc::AllocFromRun() thread-local : 0x" << std::hex 731 << reinterpret_cast<intptr_t>(slot_addr) 732 << "-0x" << (reinterpret_cast<intptr_t>(slot_addr) + bracket_size) 733 << "(" << std::dec << (bracket_size) << ")"; 734 } 735 *bytes_allocated = bracket_size; 736 *usable_size = bracket_size; 737 } else { 738 // Use the (shared) current run. 739 MutexLock mu(self, *size_bracket_locks_[idx]); 740 slot_addr = AllocFromCurrentRunUnlocked(self, idx); 741 if (kTraceRosAlloc) { 742 LOG(INFO) << "RosAlloc::AllocFromRun() : 0x" << std::hex 743 << reinterpret_cast<intptr_t>(slot_addr) 744 << "-0x" << (reinterpret_cast<intptr_t>(slot_addr) + bracket_size) 745 << "(" << std::dec << (bracket_size) << ")"; 746 } 747 if (LIKELY(slot_addr != nullptr)) { 748 *bytes_allocated = bracket_size; 749 *usable_size = bracket_size; 750 *bytes_tl_bulk_allocated = bracket_size; 751 } 752 } 753 // Caller verifies that it is all 0. 754 return slot_addr; 755 } 756 757 size_t RosAlloc::FreeFromRun(Thread* self, void* ptr, Run* run) { 758 DCHECK_EQ(run->magic_num_, kMagicNum); 759 DCHECK_LT(run, ptr); 760 DCHECK_LT(ptr, run->End()); 761 const size_t idx = run->size_bracket_idx_; 762 const size_t bracket_size = bracketSizes[idx]; 763 bool run_was_full = false; 764 MutexLock brackets_mu(self, *size_bracket_locks_[idx]); 765 if (kIsDebugBuild) { 766 run_was_full = run->IsFull(); 767 } 768 if (kTraceRosAlloc) { 769 LOG(INFO) << "RosAlloc::FreeFromRun() : 0x" << std::hex << reinterpret_cast<intptr_t>(ptr); 770 } 771 if (LIKELY(run->IsThreadLocal())) { 772 // It's a thread-local run. Just mark the thread-local free bit map and return. 773 DCHECK_LT(run->size_bracket_idx_, kNumThreadLocalSizeBrackets); 774 DCHECK(non_full_runs_[idx].find(run) == non_full_runs_[idx].end()); 775 DCHECK(full_runs_[idx].find(run) == full_runs_[idx].end()); 776 run->AddToThreadLocalFreeList(ptr); 777 if (kTraceRosAlloc) { 778 LOG(INFO) << "RosAlloc::FreeFromRun() : Freed a slot in a thread local run 0x" << std::hex 779 << reinterpret_cast<intptr_t>(run); 780 } 781 // A thread local run will be kept as a thread local even if it's become all free. 782 return bracket_size; 783 } 784 // Free the slot in the run. 785 run->FreeSlot(ptr); 786 auto* non_full_runs = &non_full_runs_[idx]; 787 if (run->IsAllFree()) { 788 // It has just become completely free. Free the pages of this run. 789 std::set<Run*>::iterator pos = non_full_runs->find(run); 790 if (pos != non_full_runs->end()) { 791 non_full_runs->erase(pos); 792 if (kTraceRosAlloc) { 793 LOG(INFO) << "RosAlloc::FreeFromRun() : Erased run 0x" << std::hex 794 << reinterpret_cast<intptr_t>(run) << " from non_full_runs_"; 795 } 796 } 797 if (run == current_runs_[idx]) { 798 current_runs_[idx] = dedicated_full_run_; 799 } 800 DCHECK(non_full_runs_[idx].find(run) == non_full_runs_[idx].end()); 801 DCHECK(full_runs_[idx].find(run) == full_runs_[idx].end()); 802 run->ZeroHeaderAndSlotHeaders(); 803 { 804 MutexLock lock_mu(self, lock_); 805 FreePages(self, run, true); 806 } 807 } else { 808 // It is not completely free. If it wasn't the current run or 809 // already in the non-full run set (i.e., it was full) insert it 810 // into the non-full run set. 811 if (run != current_runs_[idx]) { 812 auto* full_runs = kIsDebugBuild ? &full_runs_[idx] : nullptr; 813 auto pos = non_full_runs->find(run); 814 if (pos == non_full_runs->end()) { 815 DCHECK(run_was_full); 816 DCHECK(full_runs->find(run) != full_runs->end()); 817 if (kIsDebugBuild) { 818 full_runs->erase(run); 819 if (kTraceRosAlloc) { 820 LOG(INFO) << "RosAlloc::FreeFromRun() : Erased run 0x" << std::hex 821 << reinterpret_cast<intptr_t>(run) << " from full_runs_"; 822 } 823 } 824 non_full_runs->insert(run); 825 DCHECK(!run->IsFull()); 826 if (kTraceRosAlloc) { 827 LOG(INFO) << "RosAlloc::FreeFromRun() : Inserted run 0x" << std::hex 828 << reinterpret_cast<intptr_t>(run) 829 << " into non_full_runs_[" << std::dec << idx << "]"; 830 } 831 } 832 } 833 } 834 return bracket_size; 835 } 836 837 template<bool kUseTail> 838 std::string RosAlloc::Run::FreeListToStr(SlotFreeList<kUseTail>* free_list) { 839 std::string free_list_str; 840 const uint8_t idx = size_bracket_idx_; 841 const size_t bracket_size = bracketSizes[idx]; 842 for (Slot* slot = free_list->Head(); slot != nullptr; slot = slot->Next()) { 843 bool is_last = slot->Next() == nullptr; 844 uintptr_t slot_offset = reinterpret_cast<uintptr_t>(slot) - 845 reinterpret_cast<uintptr_t>(FirstSlot()); 846 DCHECK_EQ(slot_offset % bracket_size, 0U); 847 uintptr_t slot_idx = slot_offset / bracket_size; 848 if (!is_last) { 849 free_list_str.append(StringPrintf("%u-", static_cast<uint32_t>(slot_idx))); 850 } else { 851 free_list_str.append(StringPrintf("%u", static_cast<uint32_t>(slot_idx))); 852 } 853 } 854 return free_list_str; 855 } 856 857 std::string RosAlloc::Run::Dump() { 858 size_t idx = size_bracket_idx_; 859 std::ostringstream stream; 860 stream << "RosAlloc Run = " << reinterpret_cast<void*>(this) 861 << "{ magic_num=" << static_cast<int>(magic_num_) 862 << " size_bracket_idx=" << idx 863 << " is_thread_local=" << static_cast<int>(is_thread_local_) 864 << " to_be_bulk_freed=" << static_cast<int>(to_be_bulk_freed_) 865 << " free_list=" << FreeListToStr(&free_list_) 866 << " bulk_free_list=" << FreeListToStr(&bulk_free_list_) 867 << " thread_local_list=" << FreeListToStr(&thread_local_free_list_) 868 << " }" << std::endl; 869 return stream.str(); 870 } 871 872 void RosAlloc::Run::FreeSlot(void* ptr) { 873 DCHECK(!IsThreadLocal()); 874 const uint8_t idx = size_bracket_idx_; 875 const size_t bracket_size = bracketSizes[idx]; 876 Slot* slot = ToSlot(ptr); 877 // Zero out the memory. 878 // TODO: Investigate alternate memset since ptr is guaranteed to be aligned to 16. 879 memset(slot, 0, bracket_size); 880 free_list_.Add(slot); 881 if (kTraceRosAlloc) { 882 LOG(INFO) << "RosAlloc::Run::FreeSlot() : " << slot 883 << ", bracket_size=" << std::dec << bracket_size << ", slot_idx=" << SlotIndex(slot); 884 } 885 } 886 887 inline bool RosAlloc::Run::MergeThreadLocalFreeListToFreeList(bool* is_all_free_after_out) { 888 DCHECK(IsThreadLocal()); 889 // Merge the thread local free list into the free list and clear the thread local free list. 890 const uint8_t idx = size_bracket_idx_; 891 bool thread_local_free_list_size = thread_local_free_list_.Size(); 892 const size_t size_before = free_list_.Size(); 893 free_list_.Merge(&thread_local_free_list_); 894 const size_t size_after = free_list_.Size(); 895 DCHECK_EQ(size_before < size_after, thread_local_free_list_size > 0); 896 DCHECK_LE(size_before, size_after); 897 *is_all_free_after_out = free_list_.Size() == numOfSlots[idx]; 898 // Return true at least one slot was added to the free list. 899 return size_before < size_after; 900 } 901 902 inline void RosAlloc::Run::MergeBulkFreeListToFreeList() { 903 DCHECK(!IsThreadLocal()); 904 // Merge the bulk free list into the free list and clear the bulk free list. 905 free_list_.Merge(&bulk_free_list_); 906 } 907 908 inline void RosAlloc::Run::MergeBulkFreeListToThreadLocalFreeList() { 909 DCHECK(IsThreadLocal()); 910 // Merge the bulk free list into the thread local free list and clear the bulk free list. 911 thread_local_free_list_.Merge(&bulk_free_list_); 912 } 913 914 inline void RosAlloc::Run::AddToThreadLocalFreeList(void* ptr) { 915 DCHECK(IsThreadLocal()); 916 AddToFreeListShared(ptr, &thread_local_free_list_, __FUNCTION__); 917 } 918 919 inline size_t RosAlloc::Run::AddToBulkFreeList(void* ptr) { 920 return AddToFreeListShared(ptr, &bulk_free_list_, __FUNCTION__); 921 } 922 923 inline size_t RosAlloc::Run::AddToFreeListShared(void* ptr, 924 SlotFreeList<true>* free_list, 925 const char* caller_name) { 926 const uint8_t idx = size_bracket_idx_; 927 const size_t bracket_size = bracketSizes[idx]; 928 Slot* slot = ToSlot(ptr); 929 memset(slot, 0, bracket_size); 930 free_list->Add(slot); 931 if (kTraceRosAlloc) { 932 LOG(INFO) << "RosAlloc::Run::" << caller_name << "() : " << ptr 933 << ", bracket_size=" << std::dec << bracket_size << ", slot_idx=" << SlotIndex(slot); 934 } 935 return bracket_size; 936 } 937 938 inline void RosAlloc::Run::ZeroHeaderAndSlotHeaders() { 939 DCHECK(IsAllFree()); 940 const uint8_t idx = size_bracket_idx_; 941 // Zero the slot header (next pointers). 942 for (Slot* slot = free_list_.Head(); slot != nullptr; ) { 943 Slot* next_slot = slot->Next(); 944 slot->Clear(); 945 slot = next_slot; 946 } 947 // Zero the header. 948 memset(this, 0, headerSizes[idx]); 949 // Check that the entire run is all zero. 950 if (kIsDebugBuild) { 951 const size_t size = numOfPages[idx] * kPageSize; 952 const uintptr_t* word_ptr = reinterpret_cast<uintptr_t*>(this); 953 for (size_t i = 0; i < size / sizeof(uintptr_t); ++i) { 954 CHECK_EQ(word_ptr[i], 0U) << "words don't match at index " << i; 955 } 956 } 957 } 958 959 inline void RosAlloc::Run::ZeroData() { 960 const uint8_t idx = size_bracket_idx_; 961 uint8_t* slot_begin = reinterpret_cast<uint8_t*>(FirstSlot()); 962 memset(slot_begin, 0, numOfSlots[idx] * bracketSizes[idx]); 963 } 964 965 void RosAlloc::Run::InspectAllSlots(void (*handler)(void* start, void* end, size_t used_bytes, void* callback_arg), 966 void* arg) { 967 size_t idx = size_bracket_idx_; 968 uint8_t* slot_base = reinterpret_cast<uint8_t*>(this) + headerSizes[idx]; 969 size_t num_slots = numOfSlots[idx]; 970 size_t bracket_size = IndexToBracketSize(idx); 971 DCHECK_EQ(slot_base + num_slots * bracket_size, 972 reinterpret_cast<uint8_t*>(this) + numOfPages[idx] * kPageSize); 973 // Free slots are on the free list and the allocated/used slots are not. We traverse the free list 974 // to find out and record which slots are free in the is_free array. 975 std::unique_ptr<bool[]> is_free(new bool[num_slots]()); // zero initialized 976 for (Slot* slot = free_list_.Head(); slot != nullptr; slot = slot->Next()) { 977 size_t slot_idx = SlotIndex(slot); 978 DCHECK_LT(slot_idx, num_slots); 979 is_free[slot_idx] = true; 980 } 981 if (IsThreadLocal()) { 982 for (Slot* slot = thread_local_free_list_.Head(); slot != nullptr; slot = slot->Next()) { 983 size_t slot_idx = SlotIndex(slot); 984 DCHECK_LT(slot_idx, num_slots); 985 is_free[slot_idx] = true; 986 } 987 } 988 for (size_t slot_idx = 0; slot_idx < num_slots; ++slot_idx) { 989 uint8_t* slot_addr = slot_base + slot_idx * bracket_size; 990 if (!is_free[slot_idx]) { 991 handler(slot_addr, slot_addr + bracket_size, bracket_size, arg); 992 } else { 993 handler(slot_addr, slot_addr + bracket_size, 0, arg); 994 } 995 } 996 } 997 998 // If true, read the page map entries in BulkFree() without using the 999 // lock for better performance, assuming that the existence of an 1000 // allocated chunk/pointer being freed in BulkFree() guarantees that 1001 // the page map entry won't change. Disabled for now. 1002 static constexpr bool kReadPageMapEntryWithoutLockInBulkFree = true; 1003 1004 size_t RosAlloc::BulkFree(Thread* self, void** ptrs, size_t num_ptrs) { 1005 size_t freed_bytes = 0; 1006 if ((false)) { 1007 // Used only to test Free() as GC uses only BulkFree(). 1008 for (size_t i = 0; i < num_ptrs; ++i) { 1009 freed_bytes += FreeInternal(self, ptrs[i]); 1010 } 1011 return freed_bytes; 1012 } 1013 1014 WriterMutexLock wmu(self, bulk_free_lock_); 1015 1016 // First mark slots to free in the bulk free bit map without locking the 1017 // size bracket locks. On host, unordered_set is faster than vector + flag. 1018 #ifdef ART_TARGET_ANDROID 1019 std::vector<Run*> runs; 1020 #else 1021 std::unordered_set<Run*, hash_run, eq_run> runs; 1022 #endif 1023 for (size_t i = 0; i < num_ptrs; i++) { 1024 void* ptr = ptrs[i]; 1025 DCHECK_LE(base_, ptr); 1026 DCHECK_LT(ptr, base_ + footprint_); 1027 size_t pm_idx = RoundDownToPageMapIndex(ptr); 1028 Run* run = nullptr; 1029 if (kReadPageMapEntryWithoutLockInBulkFree) { 1030 // Read the page map entries without locking the lock. 1031 uint8_t page_map_entry = page_map_[pm_idx]; 1032 if (kTraceRosAlloc) { 1033 LOG(INFO) << "RosAlloc::BulkFree() : " << std::hex << ptr << ", pm_idx=" 1034 << std::dec << pm_idx 1035 << ", page_map_entry=" << static_cast<int>(page_map_entry); 1036 } 1037 if (LIKELY(page_map_entry == kPageMapRun)) { 1038 run = reinterpret_cast<Run*>(base_ + pm_idx * kPageSize); 1039 } else if (LIKELY(page_map_entry == kPageMapRunPart)) { 1040 size_t pi = pm_idx; 1041 // Find the beginning of the run. 1042 do { 1043 --pi; 1044 DCHECK_LT(pi, capacity_ / kPageSize); 1045 } while (page_map_[pi] != kPageMapRun); 1046 run = reinterpret_cast<Run*>(base_ + pi * kPageSize); 1047 } else if (page_map_entry == kPageMapLargeObject) { 1048 MutexLock mu(self, lock_); 1049 freed_bytes += FreePages(self, ptr, false); 1050 continue; 1051 } else { 1052 LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(page_map_entry); 1053 } 1054 } else { 1055 // Read the page map entries with a lock. 1056 MutexLock mu(self, lock_); 1057 DCHECK_LT(pm_idx, page_map_size_); 1058 uint8_t page_map_entry = page_map_[pm_idx]; 1059 if (kTraceRosAlloc) { 1060 LOG(INFO) << "RosAlloc::BulkFree() : " << std::hex << ptr << ", pm_idx=" 1061 << std::dec << pm_idx 1062 << ", page_map_entry=" << static_cast<int>(page_map_entry); 1063 } 1064 if (LIKELY(page_map_entry == kPageMapRun)) { 1065 run = reinterpret_cast<Run*>(base_ + pm_idx * kPageSize); 1066 } else if (LIKELY(page_map_entry == kPageMapRunPart)) { 1067 size_t pi = pm_idx; 1068 // Find the beginning of the run. 1069 do { 1070 --pi; 1071 DCHECK_LT(pi, capacity_ / kPageSize); 1072 } while (page_map_[pi] != kPageMapRun); 1073 run = reinterpret_cast<Run*>(base_ + pi * kPageSize); 1074 } else if (page_map_entry == kPageMapLargeObject) { 1075 freed_bytes += FreePages(self, ptr, false); 1076 continue; 1077 } else { 1078 LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(page_map_entry); 1079 } 1080 } 1081 DCHECK(run != nullptr); 1082 DCHECK_EQ(run->magic_num_, kMagicNum); 1083 // Set the bit in the bulk free bit map. 1084 freed_bytes += run->AddToBulkFreeList(ptr); 1085 #ifdef ART_TARGET_ANDROID 1086 if (!run->to_be_bulk_freed_) { 1087 run->to_be_bulk_freed_ = true; 1088 runs.push_back(run); 1089 } 1090 #else 1091 runs.insert(run); 1092 #endif 1093 } 1094 1095 // Now, iterate over the affected runs and update the alloc bit map 1096 // based on the bulk free bit map (for non-thread-local runs) and 1097 // union the bulk free bit map into the thread-local free bit map 1098 // (for thread-local runs.) 1099 for (Run* run : runs) { 1100 #ifdef ART_TARGET_ANDROID 1101 DCHECK(run->to_be_bulk_freed_); 1102 run->to_be_bulk_freed_ = false; 1103 #endif 1104 size_t idx = run->size_bracket_idx_; 1105 MutexLock brackets_mu(self, *size_bracket_locks_[idx]); 1106 if (run->IsThreadLocal()) { 1107 DCHECK_LT(run->size_bracket_idx_, kNumThreadLocalSizeBrackets); 1108 DCHECK(non_full_runs_[idx].find(run) == non_full_runs_[idx].end()); 1109 DCHECK(full_runs_[idx].find(run) == full_runs_[idx].end()); 1110 run->MergeBulkFreeListToThreadLocalFreeList(); 1111 if (kTraceRosAlloc) { 1112 LOG(INFO) << "RosAlloc::BulkFree() : Freed slot(s) in a thread local run 0x" 1113 << std::hex << reinterpret_cast<intptr_t>(run); 1114 } 1115 DCHECK(run->IsThreadLocal()); 1116 // A thread local run will be kept as a thread local even if 1117 // it's become all free. 1118 } else { 1119 bool run_was_full = run->IsFull(); 1120 run->MergeBulkFreeListToFreeList(); 1121 if (kTraceRosAlloc) { 1122 LOG(INFO) << "RosAlloc::BulkFree() : Freed slot(s) in a run 0x" << std::hex 1123 << reinterpret_cast<intptr_t>(run); 1124 } 1125 // Check if the run should be moved to non_full_runs_ or 1126 // free_page_runs_. 1127 auto* non_full_runs = &non_full_runs_[idx]; 1128 auto* full_runs = kIsDebugBuild ? &full_runs_[idx] : nullptr; 1129 if (run->IsAllFree()) { 1130 // It has just become completely free. Free the pages of the 1131 // run. 1132 bool run_was_current = run == current_runs_[idx]; 1133 if (run_was_current) { 1134 DCHECK(full_runs->find(run) == full_runs->end()); 1135 DCHECK(non_full_runs->find(run) == non_full_runs->end()); 1136 // If it was a current run, reuse it. 1137 } else if (run_was_full) { 1138 // If it was full, remove it from the full run set (debug 1139 // only.) 1140 if (kIsDebugBuild) { 1141 std::unordered_set<Run*, hash_run, eq_run>::iterator pos = full_runs->find(run); 1142 DCHECK(pos != full_runs->end()); 1143 full_runs->erase(pos); 1144 if (kTraceRosAlloc) { 1145 LOG(INFO) << "RosAlloc::BulkFree() : Erased run 0x" << std::hex 1146 << reinterpret_cast<intptr_t>(run) 1147 << " from full_runs_"; 1148 } 1149 DCHECK(full_runs->find(run) == full_runs->end()); 1150 } 1151 } else { 1152 // If it was in a non full run set, remove it from the set. 1153 DCHECK(full_runs->find(run) == full_runs->end()); 1154 DCHECK(non_full_runs->find(run) != non_full_runs->end()); 1155 non_full_runs->erase(run); 1156 if (kTraceRosAlloc) { 1157 LOG(INFO) << "RosAlloc::BulkFree() : Erased run 0x" << std::hex 1158 << reinterpret_cast<intptr_t>(run) 1159 << " from non_full_runs_"; 1160 } 1161 DCHECK(non_full_runs->find(run) == non_full_runs->end()); 1162 } 1163 if (!run_was_current) { 1164 run->ZeroHeaderAndSlotHeaders(); 1165 MutexLock lock_mu(self, lock_); 1166 FreePages(self, run, true); 1167 } 1168 } else { 1169 // It is not completely free. If it wasn't the current run or 1170 // already in the non-full run set (i.e., it was full) insert 1171 // it into the non-full run set. 1172 if (run == current_runs_[idx]) { 1173 DCHECK(non_full_runs->find(run) == non_full_runs->end()); 1174 DCHECK(full_runs->find(run) == full_runs->end()); 1175 // If it was a current run, keep it. 1176 } else if (run_was_full) { 1177 // If it was full, remove it from the full run set (debug 1178 // only) and insert into the non-full run set. 1179 DCHECK(full_runs->find(run) != full_runs->end()); 1180 DCHECK(non_full_runs->find(run) == non_full_runs->end()); 1181 if (kIsDebugBuild) { 1182 full_runs->erase(run); 1183 if (kTraceRosAlloc) { 1184 LOG(INFO) << "RosAlloc::BulkFree() : Erased run 0x" << std::hex 1185 << reinterpret_cast<intptr_t>(run) 1186 << " from full_runs_"; 1187 } 1188 } 1189 non_full_runs->insert(run); 1190 if (kTraceRosAlloc) { 1191 LOG(INFO) << "RosAlloc::BulkFree() : Inserted run 0x" << std::hex 1192 << reinterpret_cast<intptr_t>(run) 1193 << " into non_full_runs_[" << std::dec << idx; 1194 } 1195 } else { 1196 // If it was not full, so leave it in the non full run set. 1197 DCHECK(full_runs->find(run) == full_runs->end()); 1198 DCHECK(non_full_runs->find(run) != non_full_runs->end()); 1199 } 1200 } 1201 } 1202 } 1203 return freed_bytes; 1204 } 1205 1206 std::string RosAlloc::DumpPageMap() { 1207 std::ostringstream stream; 1208 stream << "RosAlloc PageMap: " << std::endl; 1209 lock_.AssertHeld(Thread::Current()); 1210 size_t end = page_map_size_; 1211 FreePageRun* curr_fpr = nullptr; 1212 size_t curr_fpr_size = 0; 1213 size_t remaining_curr_fpr_size = 0; 1214 size_t num_running_empty_pages = 0; 1215 for (size_t i = 0; i < end; ++i) { 1216 uint8_t pm = page_map_[i]; 1217 switch (pm) { 1218 case kPageMapReleased: 1219 // Fall-through. 1220 case kPageMapEmpty: { 1221 FreePageRun* fpr = reinterpret_cast<FreePageRun*>(base_ + i * kPageSize); 1222 if (free_page_runs_.find(fpr) != free_page_runs_.end()) { 1223 // Encountered a fresh free page run. 1224 DCHECK_EQ(remaining_curr_fpr_size, static_cast<size_t>(0)); 1225 DCHECK(fpr->IsFree()); 1226 DCHECK(curr_fpr == nullptr); 1227 DCHECK_EQ(curr_fpr_size, static_cast<size_t>(0)); 1228 curr_fpr = fpr; 1229 curr_fpr_size = fpr->ByteSize(this); 1230 DCHECK_EQ(curr_fpr_size % kPageSize, static_cast<size_t>(0)); 1231 remaining_curr_fpr_size = curr_fpr_size - kPageSize; 1232 stream << "[" << i << "]=" << (pm == kPageMapReleased ? "Released" : "Empty") 1233 << " (FPR start) fpr_size=" << curr_fpr_size 1234 << " remaining_fpr_size=" << remaining_curr_fpr_size << std::endl; 1235 if (remaining_curr_fpr_size == 0) { 1236 // Reset at the end of the current free page run. 1237 curr_fpr = nullptr; 1238 curr_fpr_size = 0; 1239 } 1240 stream << "curr_fpr=0x" << std::hex << reinterpret_cast<intptr_t>(curr_fpr) << std::endl; 1241 DCHECK_EQ(num_running_empty_pages, static_cast<size_t>(0)); 1242 } else { 1243 // Still part of the current free page run. 1244 DCHECK_NE(num_running_empty_pages, static_cast<size_t>(0)); 1245 DCHECK(curr_fpr != nullptr && curr_fpr_size > 0 && remaining_curr_fpr_size > 0); 1246 DCHECK_EQ(remaining_curr_fpr_size % kPageSize, static_cast<size_t>(0)); 1247 DCHECK_GE(remaining_curr_fpr_size, static_cast<size_t>(kPageSize)); 1248 remaining_curr_fpr_size -= kPageSize; 1249 stream << "[" << i << "]=Empty (FPR part)" 1250 << " remaining_fpr_size=" << remaining_curr_fpr_size << std::endl; 1251 if (remaining_curr_fpr_size == 0) { 1252 // Reset at the end of the current free page run. 1253 curr_fpr = nullptr; 1254 curr_fpr_size = 0; 1255 } 1256 } 1257 num_running_empty_pages++; 1258 break; 1259 } 1260 case kPageMapLargeObject: { 1261 DCHECK_EQ(remaining_curr_fpr_size, static_cast<size_t>(0)); 1262 num_running_empty_pages = 0; 1263 stream << "[" << i << "]=Large (start)" << std::endl; 1264 break; 1265 } 1266 case kPageMapLargeObjectPart: 1267 DCHECK_EQ(remaining_curr_fpr_size, static_cast<size_t>(0)); 1268 num_running_empty_pages = 0; 1269 stream << "[" << i << "]=Large (part)" << std::endl; 1270 break; 1271 case kPageMapRun: { 1272 DCHECK_EQ(remaining_curr_fpr_size, static_cast<size_t>(0)); 1273 num_running_empty_pages = 0; 1274 Run* run = reinterpret_cast<Run*>(base_ + i * kPageSize); 1275 size_t idx = run->size_bracket_idx_; 1276 stream << "[" << i << "]=Run (start)" 1277 << " idx=" << idx 1278 << " numOfPages=" << numOfPages[idx] 1279 << " is_thread_local=" << run->is_thread_local_ 1280 << " is_all_free=" << (run->IsAllFree() ? 1 : 0) 1281 << std::endl; 1282 break; 1283 } 1284 case kPageMapRunPart: 1285 DCHECK_EQ(remaining_curr_fpr_size, static_cast<size_t>(0)); 1286 num_running_empty_pages = 0; 1287 stream << "[" << i << "]=Run (part)" << std::endl; 1288 break; 1289 default: 1290 stream << "[" << i << "]=Unrecognizable page map type: " << pm; 1291 break; 1292 } 1293 } 1294 return stream.str(); 1295 } 1296 1297 size_t RosAlloc::UsableSize(const void* ptr) { 1298 DCHECK_LE(base_, ptr); 1299 DCHECK_LT(ptr, base_ + footprint_); 1300 size_t pm_idx = RoundDownToPageMapIndex(ptr); 1301 MutexLock mu(Thread::Current(), lock_); 1302 switch (page_map_[pm_idx]) { 1303 case kPageMapReleased: 1304 // Fall-through. 1305 case kPageMapEmpty: 1306 LOG(FATAL) << "Unreachable - " << __PRETTY_FUNCTION__ << ": pm_idx=" << pm_idx << ", ptr=" 1307 << std::hex << reinterpret_cast<intptr_t>(ptr); 1308 break; 1309 case kPageMapLargeObject: { 1310 size_t num_pages = 1; 1311 size_t idx = pm_idx + 1; 1312 size_t end = page_map_size_; 1313 while (idx < end && page_map_[idx] == kPageMapLargeObjectPart) { 1314 num_pages++; 1315 idx++; 1316 } 1317 return num_pages * kPageSize; 1318 } 1319 case kPageMapLargeObjectPart: 1320 LOG(FATAL) << "Unreachable - " << __PRETTY_FUNCTION__ << ": pm_idx=" << pm_idx << ", ptr=" 1321 << std::hex << reinterpret_cast<intptr_t>(ptr); 1322 break; 1323 case kPageMapRun: 1324 case kPageMapRunPart: { 1325 // Find the beginning of the run. 1326 while (page_map_[pm_idx] != kPageMapRun) { 1327 pm_idx--; 1328 DCHECK_LT(pm_idx, capacity_ / kPageSize); 1329 } 1330 DCHECK_EQ(page_map_[pm_idx], kPageMapRun); 1331 Run* run = reinterpret_cast<Run*>(base_ + pm_idx * kPageSize); 1332 DCHECK_EQ(run->magic_num_, kMagicNum); 1333 size_t idx = run->size_bracket_idx_; 1334 size_t offset_from_slot_base = reinterpret_cast<const uint8_t*>(ptr) 1335 - (reinterpret_cast<uint8_t*>(run) + headerSizes[idx]); 1336 DCHECK_EQ(offset_from_slot_base % bracketSizes[idx], static_cast<size_t>(0)); 1337 return IndexToBracketSize(idx); 1338 } 1339 default: { 1340 LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(page_map_[pm_idx]); 1341 break; 1342 } 1343 } 1344 return 0; 1345 } 1346 1347 bool RosAlloc::Trim() { 1348 MutexLock mu(Thread::Current(), lock_); 1349 FreePageRun* last_free_page_run; 1350 DCHECK_EQ(footprint_ % kPageSize, static_cast<size_t>(0)); 1351 auto it = free_page_runs_.rbegin(); 1352 if (it != free_page_runs_.rend() && (last_free_page_run = *it)->End(this) == base_ + footprint_) { 1353 // Remove the last free page run, if any. 1354 DCHECK(last_free_page_run->IsFree()); 1355 DCHECK(IsFreePage(ToPageMapIndex(last_free_page_run))); 1356 DCHECK_EQ(last_free_page_run->ByteSize(this) % kPageSize, static_cast<size_t>(0)); 1357 DCHECK_EQ(last_free_page_run->End(this), base_ + footprint_); 1358 free_page_runs_.erase(last_free_page_run); 1359 size_t decrement = last_free_page_run->ByteSize(this); 1360 size_t new_footprint = footprint_ - decrement; 1361 DCHECK_EQ(new_footprint % kPageSize, static_cast<size_t>(0)); 1362 size_t new_num_of_pages = new_footprint / kPageSize; 1363 DCHECK_GE(page_map_size_, new_num_of_pages); 1364 // Zero out the tail of the page map. 1365 uint8_t* zero_begin = const_cast<uint8_t*>(page_map_) + new_num_of_pages; 1366 uint8_t* madvise_begin = AlignUp(zero_begin, kPageSize); 1367 DCHECK_LE(madvise_begin, page_map_mem_map_->End()); 1368 size_t madvise_size = page_map_mem_map_->End() - madvise_begin; 1369 if (madvise_size > 0) { 1370 DCHECK_ALIGNED(madvise_begin, kPageSize); 1371 DCHECK_EQ(RoundUp(madvise_size, kPageSize), madvise_size); 1372 if (!kMadviseZeroes) { 1373 memset(madvise_begin, 0, madvise_size); 1374 } 1375 CHECK_EQ(madvise(madvise_begin, madvise_size, MADV_DONTNEED), 0); 1376 } 1377 if (madvise_begin - zero_begin) { 1378 memset(zero_begin, 0, madvise_begin - zero_begin); 1379 } 1380 page_map_size_ = new_num_of_pages; 1381 free_page_run_size_map_.resize(new_num_of_pages); 1382 DCHECK_EQ(free_page_run_size_map_.size(), new_num_of_pages); 1383 ArtRosAllocMoreCore(this, -(static_cast<intptr_t>(decrement))); 1384 if (kTraceRosAlloc) { 1385 LOG(INFO) << "RosAlloc::Trim() : decreased the footprint from " 1386 << footprint_ << " to " << new_footprint; 1387 } 1388 DCHECK_LT(new_footprint, footprint_); 1389 DCHECK_LT(new_footprint, capacity_); 1390 footprint_ = new_footprint; 1391 return true; 1392 } 1393 return false; 1394 } 1395 1396 void RosAlloc::InspectAll(void (*handler)(void* start, void* end, size_t used_bytes, void* callback_arg), 1397 void* arg) { 1398 // Note: no need to use this to release pages as we already do so in FreePages(). 1399 if (handler == nullptr) { 1400 return; 1401 } 1402 MutexLock mu(Thread::Current(), lock_); 1403 size_t pm_end = page_map_size_; 1404 size_t i = 0; 1405 while (i < pm_end) { 1406 uint8_t pm = page_map_[i]; 1407 switch (pm) { 1408 case kPageMapReleased: 1409 // Fall-through. 1410 case kPageMapEmpty: { 1411 // The start of a free page run. 1412 FreePageRun* fpr = reinterpret_cast<FreePageRun*>(base_ + i * kPageSize); 1413 DCHECK(free_page_runs_.find(fpr) != free_page_runs_.end()); 1414 size_t fpr_size = fpr->ByteSize(this); 1415 DCHECK_ALIGNED(fpr_size, kPageSize); 1416 void* start = fpr; 1417 if (kIsDebugBuild) { 1418 // In the debug build, the first page of a free page run 1419 // contains a magic number for debugging. Exclude it. 1420 start = reinterpret_cast<uint8_t*>(fpr) + kPageSize; 1421 } 1422 void* end = reinterpret_cast<uint8_t*>(fpr) + fpr_size; 1423 handler(start, end, 0, arg); 1424 size_t num_pages = fpr_size / kPageSize; 1425 if (kIsDebugBuild) { 1426 for (size_t j = i + 1; j < i + num_pages; ++j) { 1427 DCHECK(IsFreePage(j)); 1428 } 1429 } 1430 i += fpr_size / kPageSize; 1431 DCHECK_LE(i, pm_end); 1432 break; 1433 } 1434 case kPageMapLargeObject: { 1435 // The start of a large object. 1436 size_t num_pages = 1; 1437 size_t idx = i + 1; 1438 while (idx < pm_end && page_map_[idx] == kPageMapLargeObjectPart) { 1439 num_pages++; 1440 idx++; 1441 } 1442 void* start = base_ + i * kPageSize; 1443 void* end = base_ + (i + num_pages) * kPageSize; 1444 size_t used_bytes = num_pages * kPageSize; 1445 handler(start, end, used_bytes, arg); 1446 if (kIsDebugBuild) { 1447 for (size_t j = i + 1; j < i + num_pages; ++j) { 1448 DCHECK_EQ(page_map_[j], kPageMapLargeObjectPart); 1449 } 1450 } 1451 i += num_pages; 1452 DCHECK_LE(i, pm_end); 1453 break; 1454 } 1455 case kPageMapLargeObjectPart: 1456 LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm); 1457 break; 1458 case kPageMapRun: { 1459 // The start of a run. 1460 Run* run = reinterpret_cast<Run*>(base_ + i * kPageSize); 1461 DCHECK_EQ(run->magic_num_, kMagicNum); 1462 // The dedicated full run doesn't contain any real allocations, don't visit the slots in 1463 // there. 1464 run->InspectAllSlots(handler, arg); 1465 size_t num_pages = numOfPages[run->size_bracket_idx_]; 1466 if (kIsDebugBuild) { 1467 for (size_t j = i + 1; j < i + num_pages; ++j) { 1468 DCHECK_EQ(page_map_[j], kPageMapRunPart); 1469 } 1470 } 1471 i += num_pages; 1472 DCHECK_LE(i, pm_end); 1473 break; 1474 } 1475 case kPageMapRunPart: 1476 LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm); 1477 break; 1478 default: 1479 LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm); 1480 break; 1481 } 1482 } 1483 } 1484 1485 size_t RosAlloc::Footprint() { 1486 MutexLock mu(Thread::Current(), lock_); 1487 return footprint_; 1488 } 1489 1490 size_t RosAlloc::FootprintLimit() { 1491 MutexLock mu(Thread::Current(), lock_); 1492 return capacity_; 1493 } 1494 1495 void RosAlloc::SetFootprintLimit(size_t new_capacity) { 1496 MutexLock mu(Thread::Current(), lock_); 1497 DCHECK_EQ(RoundUp(new_capacity, kPageSize), new_capacity); 1498 // Only growing is supported here. But Trim() is supported. 1499 if (capacity_ < new_capacity) { 1500 CHECK_LE(new_capacity, max_capacity_); 1501 capacity_ = new_capacity; 1502 VLOG(heap) << "new capacity=" << capacity_; 1503 } 1504 } 1505 1506 // Below may be called by mutator itself just before thread termination. 1507 size_t RosAlloc::RevokeThreadLocalRuns(Thread* thread) { 1508 Thread* self = Thread::Current(); 1509 size_t free_bytes = 0U; 1510 for (size_t idx = 0; idx < kNumThreadLocalSizeBrackets; idx++) { 1511 MutexLock mu(self, *size_bracket_locks_[idx]); 1512 Run* thread_local_run = reinterpret_cast<Run*>(thread->GetRosAllocRun(idx)); 1513 CHECK(thread_local_run != nullptr); 1514 // Invalid means already revoked. 1515 DCHECK(thread_local_run->IsThreadLocal()); 1516 if (thread_local_run != dedicated_full_run_) { 1517 // Note the thread local run may not be full here. 1518 thread->SetRosAllocRun(idx, dedicated_full_run_); 1519 DCHECK_EQ(thread_local_run->magic_num_, kMagicNum); 1520 // Count the number of free slots left. 1521 size_t num_free_slots = thread_local_run->NumberOfFreeSlots(); 1522 free_bytes += num_free_slots * bracketSizes[idx]; 1523 // The above bracket index lock guards thread local free list to avoid race condition 1524 // with unioning bulk free list to thread local free list by GC thread in BulkFree. 1525 // If thread local run is true, GC thread will help update thread local free list 1526 // in BulkFree. And the latest thread local free list will be merged to free list 1527 // either when this thread local run is full or when revoking this run here. In this 1528 // case the free list wll be updated. If thread local run is false, GC thread will help 1529 // merge bulk free list in next BulkFree. 1530 // Thus no need to merge bulk free list to free list again here. 1531 bool dont_care; 1532 thread_local_run->MergeThreadLocalFreeListToFreeList(&dont_care); 1533 thread_local_run->SetIsThreadLocal(false); 1534 DCHECK(non_full_runs_[idx].find(thread_local_run) == non_full_runs_[idx].end()); 1535 DCHECK(full_runs_[idx].find(thread_local_run) == full_runs_[idx].end()); 1536 RevokeRun(self, idx, thread_local_run); 1537 } 1538 } 1539 return free_bytes; 1540 } 1541 1542 void RosAlloc::RevokeRun(Thread* self, size_t idx, Run* run) { 1543 size_bracket_locks_[idx]->AssertHeld(self); 1544 DCHECK(run != dedicated_full_run_); 1545 if (run->IsFull()) { 1546 if (kIsDebugBuild) { 1547 full_runs_[idx].insert(run); 1548 DCHECK(full_runs_[idx].find(run) != full_runs_[idx].end()); 1549 if (kTraceRosAlloc) { 1550 LOG(INFO) << __PRETTY_FUNCTION__ << " : Inserted run 0x" << std::hex 1551 << reinterpret_cast<intptr_t>(run) 1552 << " into full_runs_[" << std::dec << idx << "]"; 1553 } 1554 } 1555 } else if (run->IsAllFree()) { 1556 run->ZeroHeaderAndSlotHeaders(); 1557 MutexLock mu(self, lock_); 1558 FreePages(self, run, true); 1559 } else { 1560 non_full_runs_[idx].insert(run); 1561 DCHECK(non_full_runs_[idx].find(run) != non_full_runs_[idx].end()); 1562 if (kTraceRosAlloc) { 1563 LOG(INFO) << __PRETTY_FUNCTION__ << " : Inserted run 0x" << std::hex 1564 << reinterpret_cast<intptr_t>(run) 1565 << " into non_full_runs_[" << std::dec << idx << "]"; 1566 } 1567 } 1568 } 1569 1570 void RosAlloc::RevokeThreadUnsafeCurrentRuns() { 1571 // Revoke the current runs which share the same idx as thread local runs. 1572 Thread* self = Thread::Current(); 1573 for (size_t idx = 0; idx < kNumThreadLocalSizeBrackets; ++idx) { 1574 MutexLock mu(self, *size_bracket_locks_[idx]); 1575 if (current_runs_[idx] != dedicated_full_run_) { 1576 RevokeRun(self, idx, current_runs_[idx]); 1577 current_runs_[idx] = dedicated_full_run_; 1578 } 1579 } 1580 } 1581 1582 size_t RosAlloc::RevokeAllThreadLocalRuns() { 1583 // This is called when a mutator thread won't allocate such as at 1584 // the Zygote creation time or during the GC pause. 1585 MutexLock mu(Thread::Current(), *Locks::runtime_shutdown_lock_); 1586 MutexLock mu2(Thread::Current(), *Locks::thread_list_lock_); 1587 std::list<Thread*> thread_list = Runtime::Current()->GetThreadList()->GetList(); 1588 size_t free_bytes = 0U; 1589 for (Thread* thread : thread_list) { 1590 free_bytes += RevokeThreadLocalRuns(thread); 1591 } 1592 RevokeThreadUnsafeCurrentRuns(); 1593 return free_bytes; 1594 } 1595 1596 void RosAlloc::AssertThreadLocalRunsAreRevoked(Thread* thread) { 1597 if (kIsDebugBuild) { 1598 Thread* self = Thread::Current(); 1599 // Avoid race conditions on the bulk free bit maps with BulkFree() (GC). 1600 ReaderMutexLock wmu(self, bulk_free_lock_); 1601 for (size_t idx = 0; idx < kNumThreadLocalSizeBrackets; idx++) { 1602 MutexLock mu(self, *size_bracket_locks_[idx]); 1603 Run* thread_local_run = reinterpret_cast<Run*>(thread->GetRosAllocRun(idx)); 1604 DCHECK(thread_local_run == nullptr || thread_local_run == dedicated_full_run_); 1605 } 1606 } 1607 } 1608 1609 void RosAlloc::AssertAllThreadLocalRunsAreRevoked() { 1610 if (kIsDebugBuild) { 1611 Thread* self = Thread::Current(); 1612 MutexLock shutdown_mu(self, *Locks::runtime_shutdown_lock_); 1613 MutexLock thread_list_mu(self, *Locks::thread_list_lock_); 1614 std::list<Thread*> thread_list = Runtime::Current()->GetThreadList()->GetList(); 1615 for (Thread* t : thread_list) { 1616 AssertThreadLocalRunsAreRevoked(t); 1617 } 1618 for (size_t idx = 0; idx < kNumThreadLocalSizeBrackets; ++idx) { 1619 MutexLock brackets_mu(self, *size_bracket_locks_[idx]); 1620 CHECK_EQ(current_runs_[idx], dedicated_full_run_); 1621 } 1622 } 1623 } 1624 1625 void RosAlloc::Initialize() { 1626 // bracketSizes. 1627 static_assert(kNumRegularSizeBrackets == kNumOfSizeBrackets - 2, 1628 "There should be two non-regular brackets"); 1629 for (size_t i = 0; i < kNumOfSizeBrackets; i++) { 1630 if (i < kNumThreadLocalSizeBrackets) { 1631 bracketSizes[i] = kThreadLocalBracketQuantumSize * (i + 1); 1632 } else if (i < kNumRegularSizeBrackets) { 1633 bracketSizes[i] = kBracketQuantumSize * (i - kNumThreadLocalSizeBrackets + 1) + 1634 (kThreadLocalBracketQuantumSize * kNumThreadLocalSizeBrackets); 1635 } else if (i == kNumOfSizeBrackets - 2) { 1636 bracketSizes[i] = 1 * KB; 1637 } else { 1638 DCHECK_EQ(i, kNumOfSizeBrackets - 1); 1639 bracketSizes[i] = 2 * KB; 1640 } 1641 if (kTraceRosAlloc) { 1642 LOG(INFO) << "bracketSizes[" << i << "]=" << bracketSizes[i]; 1643 } 1644 } 1645 // numOfPages. 1646 for (size_t i = 0; i < kNumOfSizeBrackets; i++) { 1647 if (i < kNumThreadLocalSizeBrackets) { 1648 numOfPages[i] = 1; 1649 } else if (i < (kNumThreadLocalSizeBrackets + kNumRegularSizeBrackets) / 2) { 1650 numOfPages[i] = 1; 1651 } else if (i < kNumRegularSizeBrackets) { 1652 numOfPages[i] = 1; 1653 } else if (i == kNumOfSizeBrackets - 2) { 1654 numOfPages[i] = 2; 1655 } else { 1656 DCHECK_EQ(i, kNumOfSizeBrackets - 1); 1657 numOfPages[i] = 4; 1658 } 1659 if (kTraceRosAlloc) { 1660 LOG(INFO) << "numOfPages[" << i << "]=" << numOfPages[i]; 1661 } 1662 } 1663 // Compute numOfSlots and slotOffsets. 1664 for (size_t i = 0; i < kNumOfSizeBrackets; i++) { 1665 size_t bracket_size = bracketSizes[i]; 1666 size_t run_size = kPageSize * numOfPages[i]; 1667 size_t max_num_of_slots = run_size / bracket_size; 1668 // Compute the actual number of slots by taking the header and 1669 // alignment into account. 1670 size_t fixed_header_size = RoundUp(Run::fixed_header_size(), sizeof(uint64_t)); 1671 DCHECK_EQ(fixed_header_size, 80U); 1672 size_t header_size = 0; 1673 size_t num_of_slots = 0; 1674 // Search for the maximum number of slots that allows enough space 1675 // for the header. 1676 for (int s = max_num_of_slots; s >= 0; s--) { 1677 size_t tmp_slots_size = bracket_size * s; 1678 size_t tmp_unaligned_header_size = fixed_header_size; 1679 // Align up the unaligned header size. bracket_size may not be a power of two. 1680 size_t tmp_header_size = (tmp_unaligned_header_size % bracket_size == 0) ? 1681 tmp_unaligned_header_size : 1682 tmp_unaligned_header_size + (bracket_size - tmp_unaligned_header_size % bracket_size); 1683 DCHECK_EQ(tmp_header_size % bracket_size, 0U); 1684 DCHECK_EQ(tmp_header_size % sizeof(uint64_t), 0U); 1685 if (tmp_slots_size + tmp_header_size <= run_size) { 1686 // Found the right number of slots, that is, there was enough 1687 // space for the header (including the bit maps.) 1688 num_of_slots = s; 1689 header_size = tmp_header_size; 1690 break; 1691 } 1692 } 1693 DCHECK_GT(num_of_slots, 0U) << i; 1694 DCHECK_GT(header_size, 0U) << i; 1695 // Add the padding for the alignment remainder. 1696 header_size += run_size % bracket_size; 1697 DCHECK_EQ(header_size + num_of_slots * bracket_size, run_size); 1698 numOfSlots[i] = num_of_slots; 1699 headerSizes[i] = header_size; 1700 if (kTraceRosAlloc) { 1701 LOG(INFO) << "numOfSlots[" << i << "]=" << numOfSlots[i] 1702 << ", headerSizes[" << i << "]=" << headerSizes[i]; 1703 } 1704 } 1705 // Set up the dedicated full run so that nobody can successfully allocate from it. 1706 if (kIsDebugBuild) { 1707 dedicated_full_run_->magic_num_ = kMagicNum; 1708 } 1709 // It doesn't matter which size bracket we use since the main goal is to have the allocation 1710 // fail 100% of the time you attempt to allocate into the dedicated full run. 1711 dedicated_full_run_->size_bracket_idx_ = 0; 1712 DCHECK_EQ(dedicated_full_run_->FreeList()->Size(), 0U); // It looks full. 1713 dedicated_full_run_->SetIsThreadLocal(true); 1714 1715 // The smallest bracket size must be at least as large as the sizeof(Slot). 1716 DCHECK_LE(sizeof(Slot), bracketSizes[0]) << "sizeof(Slot) <= the smallest bracket size"; 1717 // Check the invariants between the max bracket sizes and the number of brackets. 1718 DCHECK_EQ(kMaxThreadLocalBracketSize, bracketSizes[kNumThreadLocalSizeBrackets - 1]); 1719 DCHECK_EQ(kMaxRegularBracketSize, bracketSizes[kNumRegularSizeBrackets - 1]); 1720 } 1721 1722 void RosAlloc::BytesAllocatedCallback(void* start ATTRIBUTE_UNUSED, void* end ATTRIBUTE_UNUSED, 1723 size_t used_bytes, void* arg) { 1724 if (used_bytes == 0) { 1725 return; 1726 } 1727 size_t* bytes_allocated = reinterpret_cast<size_t*>(arg); 1728 *bytes_allocated += used_bytes; 1729 } 1730 1731 void RosAlloc::ObjectsAllocatedCallback(void* start ATTRIBUTE_UNUSED, void* end ATTRIBUTE_UNUSED, 1732 size_t used_bytes, void* arg) { 1733 if (used_bytes == 0) { 1734 return; 1735 } 1736 size_t* objects_allocated = reinterpret_cast<size_t*>(arg); 1737 ++(*objects_allocated); 1738 } 1739 1740 void RosAlloc::Verify() { 1741 Thread* self = Thread::Current(); 1742 CHECK(Locks::mutator_lock_->IsExclusiveHeld(self)) 1743 << "The mutator locks isn't exclusively locked at " << __PRETTY_FUNCTION__; 1744 MutexLock thread_list_mu(self, *Locks::thread_list_lock_); 1745 ReaderMutexLock wmu(self, bulk_free_lock_); 1746 std::vector<Run*> runs; 1747 { 1748 MutexLock lock_mu(self, lock_); 1749 size_t pm_end = page_map_size_; 1750 size_t i = 0; 1751 size_t memory_tool_modifier = is_running_on_memory_tool_ ? 1752 2 * ::art::gc::space::kDefaultMemoryToolRedZoneBytes : // Redzones before and after. 1753 0; 1754 while (i < pm_end) { 1755 uint8_t pm = page_map_[i]; 1756 switch (pm) { 1757 case kPageMapReleased: 1758 // Fall-through. 1759 case kPageMapEmpty: { 1760 // The start of a free page run. 1761 FreePageRun* fpr = reinterpret_cast<FreePageRun*>(base_ + i * kPageSize); 1762 DCHECK_EQ(fpr->magic_num_, kMagicNumFree); 1763 CHECK(free_page_runs_.find(fpr) != free_page_runs_.end()) 1764 << "An empty page must belong to the free page run set"; 1765 size_t fpr_size = fpr->ByteSize(this); 1766 CHECK_ALIGNED(fpr_size, kPageSize) 1767 << "A free page run size isn't page-aligned : " << fpr_size; 1768 size_t num_pages = fpr_size / kPageSize; 1769 CHECK_GT(num_pages, static_cast<uintptr_t>(0)) 1770 << "A free page run size must be > 0 : " << fpr_size; 1771 for (size_t j = i + 1; j < i + num_pages; ++j) { 1772 CHECK(IsFreePage(j)) 1773 << "A mismatch between the page map table for kPageMapEmpty " 1774 << " at page index " << j 1775 << " and the free page run size : page index range : " 1776 << i << " to " << (i + num_pages) << std::endl << DumpPageMap(); 1777 } 1778 i += num_pages; 1779 CHECK_LE(i, pm_end) << "Page map index " << i << " out of range < " << pm_end 1780 << std::endl << DumpPageMap(); 1781 break; 1782 } 1783 case kPageMapLargeObject: { 1784 // The start of a large object. 1785 size_t num_pages = 1; 1786 size_t idx = i + 1; 1787 while (idx < pm_end && page_map_[idx] == kPageMapLargeObjectPart) { 1788 num_pages++; 1789 idx++; 1790 } 1791 uint8_t* start = base_ + i * kPageSize; 1792 if (is_running_on_memory_tool_) { 1793 start += ::art::gc::space::kDefaultMemoryToolRedZoneBytes; 1794 } 1795 mirror::Object* obj = reinterpret_cast<mirror::Object*>(start); 1796 size_t obj_size = obj->SizeOf(); 1797 CHECK_GT(obj_size + memory_tool_modifier, kLargeSizeThreshold) 1798 << "A rosalloc large object size must be > " << kLargeSizeThreshold; 1799 CHECK_EQ(num_pages, RoundUp(obj_size + memory_tool_modifier, kPageSize) / kPageSize) 1800 << "A rosalloc large object size " << obj_size + memory_tool_modifier 1801 << " does not match the page map table " << (num_pages * kPageSize) 1802 << std::endl << DumpPageMap(); 1803 i += num_pages; 1804 CHECK_LE(i, pm_end) << "Page map index " << i << " out of range < " << pm_end 1805 << std::endl << DumpPageMap(); 1806 break; 1807 } 1808 case kPageMapLargeObjectPart: 1809 LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm) << std::endl << DumpPageMap(); 1810 break; 1811 case kPageMapRun: { 1812 // The start of a run. 1813 Run* run = reinterpret_cast<Run*>(base_ + i * kPageSize); 1814 DCHECK_EQ(run->magic_num_, kMagicNum); 1815 size_t idx = run->size_bracket_idx_; 1816 CHECK_LT(idx, kNumOfSizeBrackets) << "Out of range size bracket index : " << idx; 1817 size_t num_pages = numOfPages[idx]; 1818 CHECK_GT(num_pages, static_cast<uintptr_t>(0)) 1819 << "Run size must be > 0 : " << num_pages; 1820 for (size_t j = i + 1; j < i + num_pages; ++j) { 1821 CHECK_EQ(page_map_[j], kPageMapRunPart) 1822 << "A mismatch between the page map table for kPageMapRunPart " 1823 << " at page index " << j 1824 << " and the run size : page index range " << i << " to " << (i + num_pages) 1825 << std::endl << DumpPageMap(); 1826 } 1827 // Don't verify the dedicated_full_run_ since it doesn't have any real allocations. 1828 runs.push_back(run); 1829 i += num_pages; 1830 CHECK_LE(i, pm_end) << "Page map index " << i << " out of range < " << pm_end 1831 << std::endl << DumpPageMap(); 1832 break; 1833 } 1834 case kPageMapRunPart: 1835 // Fall-through. 1836 default: 1837 LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm) << std::endl << DumpPageMap(); 1838 break; 1839 } 1840 } 1841 } 1842 std::list<Thread*> threads = Runtime::Current()->GetThreadList()->GetList(); 1843 for (Thread* thread : threads) { 1844 for (size_t i = 0; i < kNumThreadLocalSizeBrackets; ++i) { 1845 MutexLock brackets_mu(self, *size_bracket_locks_[i]); 1846 Run* thread_local_run = reinterpret_cast<Run*>(thread->GetRosAllocRun(i)); 1847 CHECK(thread_local_run != nullptr); 1848 CHECK(thread_local_run->IsThreadLocal()); 1849 CHECK(thread_local_run == dedicated_full_run_ || 1850 thread_local_run->size_bracket_idx_ == i); 1851 } 1852 } 1853 for (size_t i = 0; i < kNumOfSizeBrackets; i++) { 1854 MutexLock brackets_mu(self, *size_bracket_locks_[i]); 1855 Run* current_run = current_runs_[i]; 1856 CHECK(current_run != nullptr); 1857 if (current_run != dedicated_full_run_) { 1858 // The dedicated full run is currently marked as thread local. 1859 CHECK(!current_run->IsThreadLocal()); 1860 CHECK_EQ(current_run->size_bracket_idx_, i); 1861 } 1862 } 1863 // Call Verify() here for the lock order. 1864 for (auto& run : runs) { 1865 run->Verify(self, this, is_running_on_memory_tool_); 1866 } 1867 } 1868 1869 void RosAlloc::Run::Verify(Thread* self, RosAlloc* rosalloc, bool running_on_memory_tool) { 1870 DCHECK_EQ(magic_num_, kMagicNum) << "Bad magic number : " << Dump(); 1871 const size_t idx = size_bracket_idx_; 1872 CHECK_LT(idx, kNumOfSizeBrackets) << "Out of range size bracket index : " << Dump(); 1873 uint8_t* slot_base = reinterpret_cast<uint8_t*>(this) + headerSizes[idx]; 1874 const size_t num_slots = numOfSlots[idx]; 1875 size_t bracket_size = IndexToBracketSize(idx); 1876 CHECK_EQ(slot_base + num_slots * bracket_size, 1877 reinterpret_cast<uint8_t*>(this) + numOfPages[idx] * kPageSize) 1878 << "Mismatch in the end address of the run " << Dump(); 1879 // Check that the bulk free list is empty. It's only used during BulkFree(). 1880 CHECK(IsBulkFreeListEmpty()) << "The bulk free isn't empty " << Dump(); 1881 // Check the thread local runs, the current runs, and the run sets. 1882 if (IsThreadLocal()) { 1883 // If it's a thread local run, then it must be pointed to by an owner thread. 1884 bool owner_found = false; 1885 std::list<Thread*> thread_list = Runtime::Current()->GetThreadList()->GetList(); 1886 for (auto it = thread_list.begin(); it != thread_list.end(); ++it) { 1887 Thread* thread = *it; 1888 for (size_t i = 0; i < kNumThreadLocalSizeBrackets; i++) { 1889 MutexLock mu(self, *rosalloc->size_bracket_locks_[i]); 1890 Run* thread_local_run = reinterpret_cast<Run*>(thread->GetRosAllocRun(i)); 1891 if (thread_local_run == this) { 1892 CHECK(!owner_found) 1893 << "A thread local run has more than one owner thread " << Dump(); 1894 CHECK_EQ(i, idx) 1895 << "A mismatching size bracket index in a thread local run " << Dump(); 1896 owner_found = true; 1897 } 1898 } 1899 } 1900 CHECK(owner_found) << "A thread local run has no owner thread " << Dump(); 1901 } else { 1902 // If it's not thread local, check that the thread local free list is empty. 1903 CHECK(IsThreadLocalFreeListEmpty()) 1904 << "A non-thread-local run's thread local free list isn't empty " 1905 << Dump(); 1906 // Check if it's a current run for the size bracket. 1907 bool is_current_run = false; 1908 for (size_t i = 0; i < kNumOfSizeBrackets; i++) { 1909 MutexLock mu(self, *rosalloc->size_bracket_locks_[i]); 1910 Run* current_run = rosalloc->current_runs_[i]; 1911 if (idx == i) { 1912 if (this == current_run) { 1913 is_current_run = true; 1914 } 1915 } else { 1916 // If the size bucket index does not match, then it must not 1917 // be a current run. 1918 CHECK_NE(this, current_run) 1919 << "A current run points to a run with a wrong size bracket index " << Dump(); 1920 } 1921 } 1922 // If it's neither a thread local or current run, then it must be 1923 // in a run set. 1924 if (!is_current_run) { 1925 MutexLock mu(self, rosalloc->lock_); 1926 auto& non_full_runs = rosalloc->non_full_runs_[idx]; 1927 // If it's all free, it must be a free page run rather than a run. 1928 CHECK(!IsAllFree()) << "A free run must be in a free page run set " << Dump(); 1929 if (!IsFull()) { 1930 // If it's not full, it must in the non-full run set. 1931 CHECK(non_full_runs.find(this) != non_full_runs.end()) 1932 << "A non-full run isn't in the non-full run set " << Dump(); 1933 } else { 1934 // If it's full, it must in the full run set (debug build only.) 1935 if (kIsDebugBuild) { 1936 auto& full_runs = rosalloc->full_runs_[idx]; 1937 CHECK(full_runs.find(this) != full_runs.end()) 1938 << " A full run isn't in the full run set " << Dump(); 1939 } 1940 } 1941 } 1942 } 1943 // Check each slot. 1944 size_t memory_tool_modifier = running_on_memory_tool ? 1945 2 * ::art::gc::space::kDefaultMemoryToolRedZoneBytes : 1946 0U; 1947 // TODO: reuse InspectAllSlots(). 1948 std::unique_ptr<bool[]> is_free(new bool[num_slots]()); // zero initialized 1949 // Mark the free slots and the remaining ones are allocated. 1950 for (Slot* slot = free_list_.Head(); slot != nullptr; slot = slot->Next()) { 1951 size_t slot_idx = SlotIndex(slot); 1952 DCHECK_LT(slot_idx, num_slots); 1953 is_free[slot_idx] = true; 1954 } 1955 if (IsThreadLocal()) { 1956 for (Slot* slot = thread_local_free_list_.Head(); slot != nullptr; slot = slot->Next()) { 1957 size_t slot_idx = SlotIndex(slot); 1958 DCHECK_LT(slot_idx, num_slots); 1959 is_free[slot_idx] = true; 1960 } 1961 } 1962 for (size_t slot_idx = 0; slot_idx < num_slots; ++slot_idx) { 1963 uint8_t* slot_addr = slot_base + slot_idx * bracket_size; 1964 if (running_on_memory_tool) { 1965 slot_addr += ::art::gc::space::kDefaultMemoryToolRedZoneBytes; 1966 } 1967 if (!is_free[slot_idx]) { 1968 // The slot is allocated 1969 mirror::Object* obj = reinterpret_cast<mirror::Object*>(slot_addr); 1970 size_t obj_size = obj->SizeOf(); 1971 CHECK_LE(obj_size + memory_tool_modifier, kLargeSizeThreshold) 1972 << "A run slot contains a large object " << Dump(); 1973 CHECK_EQ(SizeToIndex(obj_size + memory_tool_modifier), idx) 1974 << obj->PrettyTypeOf() << " " 1975 << "obj_size=" << obj_size << "(" << obj_size + memory_tool_modifier << "), idx=" << idx 1976 << " A run slot contains an object with wrong size " << Dump(); 1977 } 1978 } 1979 } 1980 1981 size_t RosAlloc::ReleasePages() { 1982 VLOG(heap) << "RosAlloc::ReleasePages()"; 1983 DCHECK(!DoesReleaseAllPages()); 1984 Thread* self = Thread::Current(); 1985 size_t reclaimed_bytes = 0; 1986 size_t i = 0; 1987 // Check the page map size which might have changed due to grow/shrink. 1988 while (i < page_map_size_) { 1989 // Reading the page map without a lock is racy but the race is benign since it should only 1990 // result in occasionally not releasing pages which we could release. 1991 uint8_t pm = page_map_[i]; 1992 switch (pm) { 1993 case kPageMapReleased: 1994 // Fall through. 1995 case kPageMapEmpty: { 1996 // This is currently the start of a free page run. 1997 // Acquire the lock to prevent other threads racing in and modifying the page map. 1998 MutexLock mu(self, lock_); 1999 // Check that it's still empty after we acquired the lock since another thread could have 2000 // raced in and placed an allocation here. 2001 if (IsFreePage(i)) { 2002 // Free page runs can start with a released page if we coalesced a released page free 2003 // page run with an empty page run. 2004 FreePageRun* fpr = reinterpret_cast<FreePageRun*>(base_ + i * kPageSize); 2005 // There is a race condition where FreePage can coalesce fpr with the previous 2006 // free page run before we acquire lock_. In that case free_page_runs_.find will not find 2007 // a run starting at fpr. To handle this race, we skip reclaiming the page range and go 2008 // to the next page. 2009 if (free_page_runs_.find(fpr) != free_page_runs_.end()) { 2010 size_t fpr_size = fpr->ByteSize(this); 2011 DCHECK_ALIGNED(fpr_size, kPageSize); 2012 uint8_t* start = reinterpret_cast<uint8_t*>(fpr); 2013 reclaimed_bytes += ReleasePageRange(start, start + fpr_size); 2014 size_t pages = fpr_size / kPageSize; 2015 CHECK_GT(pages, 0U) << "Infinite loop probable"; 2016 i += pages; 2017 DCHECK_LE(i, page_map_size_); 2018 break; 2019 } 2020 } 2021 FALLTHROUGH_INTENDED; 2022 } 2023 case kPageMapLargeObject: // Fall through. 2024 case kPageMapLargeObjectPart: // Fall through. 2025 case kPageMapRun: // Fall through. 2026 case kPageMapRunPart: // Fall through. 2027 ++i; 2028 break; // Skip. 2029 default: 2030 LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm); 2031 break; 2032 } 2033 } 2034 return reclaimed_bytes; 2035 } 2036 2037 size_t RosAlloc::ReleasePageRange(uint8_t* start, uint8_t* end) { 2038 DCHECK_ALIGNED(start, kPageSize); 2039 DCHECK_ALIGNED(end, kPageSize); 2040 DCHECK_LT(start, end); 2041 if (kIsDebugBuild) { 2042 // In the debug build, the first page of a free page run 2043 // contains a magic number for debugging. Exclude it. 2044 start += kPageSize; 2045 2046 // Single pages won't be released. 2047 if (start == end) { 2048 return 0; 2049 } 2050 } 2051 if (!kMadviseZeroes) { 2052 // TODO: Do this when we resurrect the page instead. 2053 memset(start, 0, end - start); 2054 } 2055 CHECK_EQ(madvise(start, end - start, MADV_DONTNEED), 0); 2056 size_t pm_idx = ToPageMapIndex(start); 2057 size_t reclaimed_bytes = 0; 2058 // Calculate reclaimed bytes and upate page map. 2059 const size_t max_idx = pm_idx + (end - start) / kPageSize; 2060 for (; pm_idx < max_idx; ++pm_idx) { 2061 DCHECK(IsFreePage(pm_idx)); 2062 if (page_map_[pm_idx] == kPageMapEmpty) { 2063 // Mark the page as released and update how many bytes we released. 2064 reclaimed_bytes += kPageSize; 2065 page_map_[pm_idx] = kPageMapReleased; 2066 } 2067 } 2068 return reclaimed_bytes; 2069 } 2070 2071 void RosAlloc::LogFragmentationAllocFailure(std::ostream& os, size_t failed_alloc_bytes) { 2072 Thread* self = Thread::Current(); 2073 size_t largest_continuous_free_pages = 0; 2074 WriterMutexLock wmu(self, bulk_free_lock_); 2075 MutexLock mu(self, lock_); 2076 uint64_t total_free = 0; 2077 for (FreePageRun* fpr : free_page_runs_) { 2078 largest_continuous_free_pages = std::max(largest_continuous_free_pages, 2079 fpr->ByteSize(this)); 2080 total_free += fpr->ByteSize(this); 2081 } 2082 size_t required_bytes = 0; 2083 const char* new_buffer_msg = ""; 2084 if (failed_alloc_bytes > kLargeSizeThreshold) { 2085 // Large allocation. 2086 required_bytes = RoundUp(failed_alloc_bytes, kPageSize); 2087 } else { 2088 // Non-large allocation. 2089 required_bytes = numOfPages[SizeToIndex(failed_alloc_bytes)] * kPageSize; 2090 new_buffer_msg = " for a new buffer"; 2091 } 2092 if (required_bytes > largest_continuous_free_pages) { 2093 os << "; failed due to fragmentation (" 2094 << "required contiguous free " << required_bytes << " bytes" << new_buffer_msg 2095 << ", largest contiguous free " << largest_continuous_free_pages << " bytes" 2096 << ", total free pages " << total_free << " bytes" 2097 << ", space footprint " << footprint_ << " bytes" 2098 << ", space max capacity " << max_capacity_ << " bytes" 2099 << ")" << std::endl; 2100 } 2101 } 2102 2103 void RosAlloc::DumpStats(std::ostream& os) { 2104 Thread* self = Thread::Current(); 2105 CHECK(Locks::mutator_lock_->IsExclusiveHeld(self)) 2106 << "The mutator locks isn't exclusively locked at " << __PRETTY_FUNCTION__; 2107 size_t num_large_objects = 0; 2108 size_t num_pages_large_objects = 0; 2109 // These arrays are zero initialized. 2110 std::unique_ptr<size_t[]> num_runs(new size_t[kNumOfSizeBrackets]()); 2111 std::unique_ptr<size_t[]> num_pages_runs(new size_t[kNumOfSizeBrackets]()); 2112 std::unique_ptr<size_t[]> num_slots(new size_t[kNumOfSizeBrackets]()); 2113 std::unique_ptr<size_t[]> num_used_slots(new size_t[kNumOfSizeBrackets]()); 2114 std::unique_ptr<size_t[]> num_metadata_bytes(new size_t[kNumOfSizeBrackets]()); 2115 ReaderMutexLock rmu(self, bulk_free_lock_); 2116 MutexLock lock_mu(self, lock_); 2117 for (size_t i = 0; i < page_map_size_; ) { 2118 uint8_t pm = page_map_[i]; 2119 switch (pm) { 2120 case kPageMapReleased: 2121 case kPageMapEmpty: 2122 ++i; 2123 break; 2124 case kPageMapLargeObject: { 2125 size_t num_pages = 1; 2126 size_t idx = i + 1; 2127 while (idx < page_map_size_ && page_map_[idx] == kPageMapLargeObjectPart) { 2128 num_pages++; 2129 idx++; 2130 } 2131 num_large_objects++; 2132 num_pages_large_objects += num_pages; 2133 i += num_pages; 2134 break; 2135 } 2136 case kPageMapLargeObjectPart: 2137 LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm) << std::endl 2138 << DumpPageMap(); 2139 break; 2140 case kPageMapRun: { 2141 Run* run = reinterpret_cast<Run*>(base_ + i * kPageSize); 2142 size_t idx = run->size_bracket_idx_; 2143 size_t num_pages = numOfPages[idx]; 2144 num_runs[idx]++; 2145 num_pages_runs[idx] += num_pages; 2146 num_slots[idx] += numOfSlots[idx]; 2147 size_t num_free_slots = run->NumberOfFreeSlots(); 2148 num_used_slots[idx] += numOfSlots[idx] - num_free_slots; 2149 num_metadata_bytes[idx] += headerSizes[idx]; 2150 i += num_pages; 2151 break; 2152 } 2153 case kPageMapRunPart: 2154 // Fall-through. 2155 default: 2156 LOG(FATAL) << "Unreachable - page map type: " << static_cast<int>(pm) << std::endl 2157 << DumpPageMap(); 2158 break; 2159 } 2160 } 2161 os << "RosAlloc stats:\n"; 2162 for (size_t i = 0; i < kNumOfSizeBrackets; ++i) { 2163 os << "Bracket " << i << " (" << bracketSizes[i] << "):" 2164 << " #runs=" << num_runs[i] 2165 << " #pages=" << num_pages_runs[i] 2166 << " (" << PrettySize(num_pages_runs[i] * kPageSize) << ")" 2167 << " #metadata_bytes=" << PrettySize(num_metadata_bytes[i]) 2168 << " #slots=" << num_slots[i] << " (" << PrettySize(num_slots[i] * bracketSizes[i]) << ")" 2169 << " #used_slots=" << num_used_slots[i] 2170 << " (" << PrettySize(num_used_slots[i] * bracketSizes[i]) << ")\n"; 2171 } 2172 os << "Large #allocations=" << num_large_objects 2173 << " #pages=" << num_pages_large_objects 2174 << " (" << PrettySize(num_pages_large_objects * kPageSize) << ")\n"; 2175 size_t total_num_pages = 0; 2176 size_t total_metadata_bytes = 0; 2177 size_t total_allocated_bytes = 0; 2178 for (size_t i = 0; i < kNumOfSizeBrackets; ++i) { 2179 total_num_pages += num_pages_runs[i]; 2180 total_metadata_bytes += num_metadata_bytes[i]; 2181 total_allocated_bytes += num_used_slots[i] * bracketSizes[i]; 2182 } 2183 total_num_pages += num_pages_large_objects; 2184 total_allocated_bytes += num_pages_large_objects * kPageSize; 2185 os << "Total #total_bytes=" << PrettySize(total_num_pages * kPageSize) 2186 << " #metadata_bytes=" << PrettySize(total_metadata_bytes) 2187 << " #used_bytes=" << PrettySize(total_allocated_bytes) << "\n"; 2188 os << "\n"; 2189 } 2190 2191 } // namespace allocator 2192 } // namespace gc 2193 } // namespace art 2194