| OLD | NEW |
| 1 // Copyright (c) 2008, Google Inc. | 1 // Copyright (c) 2008, Google Inc. |
| 2 // All rights reserved. | 2 // All rights reserved. |
| 3 // | 3 // |
| 4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
| 5 // modification, are permitted provided that the following conditions are | 5 // modification, are permitted provided that the following conditions are |
| 6 // met: | 6 // met: |
| 7 // | 7 // |
| 8 // * Redistributions of source code must retain the above copyright | 8 // * Redistributions of source code must retain the above copyright |
| 9 // notice, this list of conditions and the following disclaimer. | 9 // notice, this list of conditions and the following disclaimer. |
| 10 // * Redistributions in binary form must reproduce the above | 10 // * Redistributions in binary form must reproduce the above |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 93 Span* PageHeap::New(Length n) { | 93 Span* PageHeap::New(Length n) { |
| 94 ASSERT(Check()); | 94 ASSERT(Check()); |
| 95 ASSERT(n > 0); | 95 ASSERT(n > 0); |
| 96 | 96 |
| 97 Span* result = SearchFreeAndLargeLists(n); | 97 Span* result = SearchFreeAndLargeLists(n); |
| 98 if (result != NULL) | 98 if (result != NULL) |
| 99 return result; | 99 return result; |
| 100 | 100 |
| 101 // Grow the heap and try again. | 101 // Grow the heap and try again. |
| 102 if (!GrowHeap(n)) { | 102 if (!GrowHeap(n)) { |
| 103 ASSERT(stats_.unmapped_bytes+ stats_.committed_bytes==stats_.system_bytes); | |
| 104 ASSERT(Check()); | 103 ASSERT(Check()); |
| 105 return NULL; | 104 return NULL; |
| 106 } | 105 } |
| 107 return SearchFreeAndLargeLists(n); | 106 return SearchFreeAndLargeLists(n); |
| 108 } | 107 } |
| 109 | 108 |
| 110 Span* PageHeap::AllocLarge(Length n) { | 109 Span* PageHeap::AllocLarge(Length n) { |
| 111 // find the best span (closest to n in size). | 110 // find the best span (closest to n in size). |
| 112 // The following loops implements address-ordered best-fit. | 111 // The following loops implements address-ordered best-fit. |
| 113 Span *best = NULL; | 112 Span *best = NULL; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 154 Span* leftover = NewSpan(span->start + n, extra); | 153 Span* leftover = NewSpan(span->start + n, extra); |
| 155 ASSERT(leftover->location == Span::IN_USE); | 154 ASSERT(leftover->location == Span::IN_USE); |
| 156 Event(leftover, 'U', extra); | 155 Event(leftover, 'U', extra); |
| 157 RecordSpan(leftover); | 156 RecordSpan(leftover); |
| 158 pagemap_.set(span->start + n - 1, span); // Update map from pageid to span | 157 pagemap_.set(span->start + n - 1, span); // Update map from pageid to span |
| 159 span->length = n; | 158 span->length = n; |
| 160 | 159 |
| 161 return leftover; | 160 return leftover; |
| 162 } | 161 } |
| 163 | 162 |
| 164 void PageHeap::CommitSpan(Span* span) { | |
| 165 TCMalloc_SystemCommit(reinterpret_cast<void*>(span->start << kPageShift), | |
| 166 static_cast<size_t>(span->length << kPageShift)); | |
| 167 stats_.committed_bytes += span->length << kPageShift; | |
| 168 } | |
| 169 | |
| 170 void PageHeap::DecommitSpan(Span* span) { | |
| 171 TCMalloc_SystemRelease(reinterpret_cast<void*>(span->start << kPageShift), | |
| 172 static_cast<size_t>(span->length << kPageShift)); | |
| 173 stats_.committed_bytes -= span->length << kPageShift; | |
| 174 } | |
| 175 | |
| 176 Span* PageHeap::Carve(Span* span, Length n) { | 163 Span* PageHeap::Carve(Span* span, Length n) { |
| 177 ASSERT(n > 0); | 164 ASSERT(n > 0); |
| 178 ASSERT(span->location != Span::IN_USE); | 165 ASSERT(span->location != Span::IN_USE); |
| 179 const int old_location = span->location; | 166 const int old_location = span->location; |
| 180 RemoveFromFreeList(span); | 167 RemoveFromFreeList(span); |
| 181 span->location = Span::IN_USE; | 168 span->location = Span::IN_USE; |
| 182 Event(span, 'A', n); | 169 Event(span, 'A', n); |
| 183 | 170 |
| 184 const int extra = span->length - n; | 171 const int extra = span->length - n; |
| 185 ASSERT(extra >= 0); | 172 ASSERT(extra >= 0); |
| 186 if (extra > 0) { | 173 if (extra > 0) { |
| 187 Span* leftover = NewSpan(span->start + n, extra); | 174 Span* leftover = NewSpan(span->start + n, extra); |
| 188 leftover->location = old_location; | 175 leftover->location = old_location; |
| 189 Event(leftover, 'S', extra); | 176 Event(leftover, 'S', extra); |
| 190 RecordSpan(leftover); | 177 RecordSpan(leftover); |
| 191 | |
| 192 // The previous span of |leftover| was just splitted -- no need to | |
| 193 // coalesce them. The next span of |leftover| was not previously coalesced | |
| 194 // with |span|, i.e. is NULL or has got location other than |old_location|. | |
| 195 const PageID p = leftover->start; | |
| 196 const Length len = leftover->length; | |
| 197 Span* next = GetDescriptor(p+len); | |
| 198 ASSERT (next == NULL || | |
| 199 next->location == Span::IN_USE || | |
| 200 next->location != leftover->location); | |
| 201 | |
| 202 PrependToFreeList(leftover); // Skip coalescing - no candidates possible | 178 PrependToFreeList(leftover); // Skip coalescing - no candidates possible |
| 203 span->length = n; | 179 span->length = n; |
| 204 pagemap_.set(span->start + n - 1, span); | 180 pagemap_.set(span->start + n - 1, span); |
| 205 } | 181 } |
| 206 ASSERT(Check()); | 182 ASSERT(Check()); |
| 207 if (old_location == Span::ON_RETURNED_FREELIST) { | |
| 208 // We need to recommit this address space. | |
| 209 CommitSpan(span); | |
| 210 } | |
| 211 ASSERT(span->location == Span::IN_USE); | |
| 212 ASSERT(span->length == n); | |
| 213 ASSERT(stats_.unmapped_bytes+ stats_.committed_bytes==stats_.system_bytes); | |
| 214 return span; | 183 return span; |
| 215 } | 184 } |
| 216 | 185 |
| 217 void PageHeap::Delete(Span* span) { | 186 void PageHeap::Delete(Span* span) { |
| 218 ASSERT(Check()); | 187 ASSERT(Check()); |
| 219 ASSERT(span->location == Span::IN_USE); | 188 ASSERT(span->location == Span::IN_USE); |
| 220 ASSERT(span->length > 0); | 189 ASSERT(span->length > 0); |
| 221 ASSERT(GetDescriptor(span->start) == span); | 190 ASSERT(GetDescriptor(span->start) == span); |
| 222 ASSERT(GetDescriptor(span->start + span->length - 1) == span); | 191 ASSERT(GetDescriptor(span->start + span->length - 1) == span); |
| 223 const Length n = span->length; | 192 const Length n = span->length; |
| 224 span->sizeclass = 0; | 193 span->sizeclass = 0; |
| 225 span->sample = 0; | 194 span->sample = 0; |
| 226 span->location = Span::ON_NORMAL_FREELIST; | 195 span->location = Span::ON_NORMAL_FREELIST; |
| 227 Event(span, 'D', span->length); | 196 Event(span, 'D', span->length); |
| 228 MergeIntoFreeList(span); // Coalesces if possible | 197 MergeIntoFreeList(span); // Coalesces if possible |
| 229 IncrementalScavenge(n); | 198 IncrementalScavenge(n); |
| 230 ASSERT(stats_.unmapped_bytes+ stats_.committed_bytes==stats_.system_bytes); | |
| 231 ASSERT(Check()); | 199 ASSERT(Check()); |
| 232 } | 200 } |
| 233 | 201 |
| 234 void PageHeap::MergeIntoFreeList(Span* span) { | 202 void PageHeap::MergeIntoFreeList(Span* span) { |
| 235 ASSERT(span->location != Span::IN_USE); | 203 ASSERT(span->location != Span::IN_USE); |
| 236 | 204 |
| 237 // Coalesce -- we guarantee that "p" != 0, so no bounds checking | 205 // Coalesce -- we guarantee that "p" != 0, so no bounds checking |
| 238 // necessary. We do not bother resetting the stale pagemap | 206 // necessary. We do not bother resetting the stale pagemap |
| 239 // entries for the pieces we are merging together because we only | 207 // entries for the pieces we are merging together because we only |
| 240 // care about the pagemap entries for the boundaries. | 208 // care about the pagemap entries for the boundaries. |
| 241 // | 209 // |
| 242 // Note that the adjacent spans we merge into "span" may come out of a | 210 // Note that only similar spans are merged together. For example, |
| 243 // "normal" (committed) list, and cleanly merge with our IN_USE span, which | 211 // we do not coalesce "returned" spans with "normal" spans. |
| 244 // is implicitly committed. If the adjacents spans are on the "returned" | |
| 245 // (decommitted) list, then we must get both spans into the same state before | |
| 246 // or after we coalesce them. The current code always decomits. This is | |
| 247 // achieved by blindly decommitting the entire coalesced region, which may | |
| 248 // include any combination of committed and decommitted spans, at the end of | |
| 249 // the method. | |
| 250 | |
| 251 // TODO(jar): "Always decommit" causes some extra calls to commit when we are | |
| 252 // called in GrowHeap() during an allocation :-/. We need to eval the cost of | |
| 253 // that oscillation, and possibly do something to reduce it. | |
| 254 | |
| 255 // TODO(jar): We need a better strategy for deciding to commit, or decommit, | |
| 256 // based on memory usage and free heap sizes. | |
| 257 | |
| 258 const PageID p = span->start; | 212 const PageID p = span->start; |
| 259 const Length n = span->length; | 213 const Length n = span->length; |
| 260 Span* prev = GetDescriptor(p-1); | 214 Span* prev = GetDescriptor(p-1); |
| 261 if (prev != NULL && prev->location != Span::IN_USE) { | 215 if (prev != NULL && prev->location == span->location) { |
| 262 // Merge preceding span into this span | 216 // Merge preceding span into this span |
| 263 ASSERT(prev->start + prev->length == p); | 217 ASSERT(prev->start + prev->length == p); |
| 264 const Length len = prev->length; | 218 const Length len = prev->length; |
| 265 if (prev->location == Span::ON_RETURNED_FREELIST) { | |
| 266 // We're about to put the merge span into the returned freelist and call | |
| 267 // DecommitSpan() on it, which will mark the entire span including this | |
| 268 // one as released and decrease stats_.committed_bytes by the size of the | |
| 269 // merged span. To make the math work out we temporarily increase the | |
| 270 // stats_.committed_bytes amount. | |
| 271 stats_.committed_bytes += prev->length << kPageShift; | |
| 272 } | |
| 273 RemoveFromFreeList(prev); | 219 RemoveFromFreeList(prev); |
| 274 DeleteSpan(prev); | 220 DeleteSpan(prev); |
| 275 span->start -= len; | 221 span->start -= len; |
| 276 span->length += len; | 222 span->length += len; |
| 277 pagemap_.set(span->start, span); | 223 pagemap_.set(span->start, span); |
| 278 Event(span, 'L', len); | 224 Event(span, 'L', len); |
| 279 } | 225 } |
| 280 Span* next = GetDescriptor(p+n); | 226 Span* next = GetDescriptor(p+n); |
| 281 if (next != NULL && next->location != Span::IN_USE) { | 227 if (next != NULL && next->location == span->location) { |
| 282 // Merge next span into this span | 228 // Merge next span into this span |
| 283 ASSERT(next->start == p+n); | 229 ASSERT(next->start == p+n); |
| 284 const Length len = next->length; | 230 const Length len = next->length; |
| 285 if (next->location == Span::ON_RETURNED_FREELIST) { | |
| 286 // See the comment below 'if (prev->location ...' for explanation. | |
| 287 stats_.committed_bytes += next->length << kPageShift; | |
| 288 } | |
| 289 RemoveFromFreeList(next); | 231 RemoveFromFreeList(next); |
| 290 DeleteSpan(next); | 232 DeleteSpan(next); |
| 291 span->length += len; | 233 span->length += len; |
| 292 pagemap_.set(span->start + span->length - 1, span); | 234 pagemap_.set(span->start + span->length - 1, span); |
| 293 Event(span, 'R', len); | 235 Event(span, 'R', len); |
| 294 } | 236 } |
| 295 | 237 |
| 296 Event(span, 'D', span->length); | |
| 297 span->location = Span::ON_RETURNED_FREELIST; | |
| 298 DecommitSpan(span); | |
| 299 PrependToFreeList(span); | 238 PrependToFreeList(span); |
| 300 } | 239 } |
| 301 | 240 |
| 302 void PageHeap::PrependToFreeList(Span* span) { | 241 void PageHeap::PrependToFreeList(Span* span) { |
| 303 ASSERT(span->location != Span::IN_USE); | 242 ASSERT(span->location != Span::IN_USE); |
| 304 SpanList* list = (span->length < kMaxPages) ? &free_[span->length] : &large_; | 243 SpanList* list = (span->length < kMaxPages) ? &free_[span->length] : &large_; |
| 305 if (span->location == Span::ON_NORMAL_FREELIST) { | 244 if (span->location == Span::ON_NORMAL_FREELIST) { |
| 306 stats_.free_bytes += (span->length << kPageShift); | 245 stats_.free_bytes += (span->length << kPageShift); |
| 307 DLL_Prepend(&list->normal, span); | 246 DLL_Prepend(&list->normal, span); |
| 308 } else { | 247 } else { |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 396 ASSERT(span->location == Span::IN_USE); | 335 ASSERT(span->location == Span::IN_USE); |
| 397 ASSERT(GetDescriptor(span->start) == span); | 336 ASSERT(GetDescriptor(span->start) == span); |
| 398 ASSERT(GetDescriptor(span->start+span->length-1) == span); | 337 ASSERT(GetDescriptor(span->start+span->length-1) == span); |
| 399 Event(span, 'C', sc); | 338 Event(span, 'C', sc); |
| 400 span->sizeclass = sc; | 339 span->sizeclass = sc; |
| 401 for (Length i = 1; i < span->length-1; i++) { | 340 for (Length i = 1; i < span->length-1; i++) { |
| 402 pagemap_.set(span->start+i, span); | 341 pagemap_.set(span->start+i, span); |
| 403 } | 342 } |
| 404 } | 343 } |
| 405 | 344 |
| 406 static double MiB(uint64_t bytes) { | 345 void PageHeap::GetSmallSpanStats(SmallSpanStats* result) { |
| 407 return bytes / 1048576.0; | |
| 408 } | |
| 409 | |
| 410 static double PagesToMiB(uint64_t pages) { | |
| 411 return (pages << kPageShift) / 1048576.0; | |
| 412 } | |
| 413 | |
| 414 void PageHeap::GetClassSizes(int64 class_sizes_normal[kMaxPages], | |
| 415 int64 class_sizes_returned[kMaxPages], | |
| 416 int64* normal_pages_in_spans, | |
| 417 int64* returned_pages_in_spans) { | |
| 418 | |
| 419 for (int s = 0; s < kMaxPages; s++) { | 346 for (int s = 0; s < kMaxPages; s++) { |
| 420 if (class_sizes_normal != NULL) { | 347 result->normal_length[s] = DLL_Length(&free_[s].normal); |
| 421 class_sizes_normal[s] = DLL_Length(&free_[s].normal); | 348 result->returned_length[s] = DLL_Length(&free_[s].returned); |
| 422 } | |
| 423 if (class_sizes_returned != NULL) { | |
| 424 class_sizes_returned[s] = DLL_Length(&free_[s].returned); | |
| 425 } | |
| 426 } | |
| 427 | |
| 428 if (normal_pages_in_spans != NULL) { | |
| 429 *normal_pages_in_spans = 0; | |
| 430 for (Span* s = large_.normal.next; s != &large_.normal; s = s->next) { | |
| 431 *normal_pages_in_spans += s->length;; | |
| 432 } | |
| 433 } | |
| 434 | |
| 435 if (returned_pages_in_spans != NULL) { | |
| 436 *returned_pages_in_spans = 0; | |
| 437 for (Span* s = large_.returned.next; s != &large_.returned; s = s->next) { | |
| 438 *returned_pages_in_spans += s->length; | |
| 439 } | |
| 440 } | 349 } |
| 441 } | 350 } |
| 442 | 351 |
| 443 void PageHeap::Dump(TCMalloc_Printer* out) { | 352 void PageHeap::GetLargeSpanStats(LargeSpanStats* result) { |
| 444 int nonempty_sizes = 0; | 353 result->spans = 0; |
| 445 for (int s = 0; s < kMaxPages; s++) { | 354 result->normal_pages = 0; |
| 446 if (!DLL_IsEmpty(&free_[s].normal) || !DLL_IsEmpty(&free_[s].returned)) { | 355 result->returned_pages = 0; |
| 447 nonempty_sizes++; | 356 for (Span* s = large_.normal.next; s != &large_.normal; s = s->next) { |
| 448 } | 357 result->normal_pages += s->length;; |
| 358 result->spans++; |
| 449 } | 359 } |
| 450 out->printf("------------------------------------------------\n"); | 360 for (Span* s = large_.returned.next; s != &large_.returned; s = s->next) { |
| 451 out->printf("PageHeap: %d sizes; %6.1f MiB free; %6.1f MiB unmapped\n", | 361 result->returned_pages += s->length; |
| 452 nonempty_sizes, MiB(stats_.free_bytes), | 362 result->spans++; |
| 453 MiB(stats_.unmapped_bytes)); | |
| 454 out->printf("------------------------------------------------\n"); | |
| 455 uint64_t total_normal = 0; | |
| 456 uint64_t total_returned = 0; | |
| 457 for (int s = 0; s < kMaxPages; s++) { | |
| 458 const int n_length = DLL_Length(&free_[s].normal); | |
| 459 const int r_length = DLL_Length(&free_[s].returned); | |
| 460 if (n_length + r_length > 0) { | |
| 461 uint64_t n_pages = s * n_length; | |
| 462 uint64_t r_pages = s * r_length; | |
| 463 total_normal += n_pages; | |
| 464 total_returned += r_pages; | |
| 465 out->printf("%6u pages * %6u spans ~ %6.1f MiB; %6.1f MiB cum" | |
| 466 "; unmapped: %6.1f MiB; %6.1f MiB cum\n", | |
| 467 s, | |
| 468 (n_length + r_length), | |
| 469 PagesToMiB(n_pages + r_pages), | |
| 470 PagesToMiB(total_normal + total_returned), | |
| 471 PagesToMiB(r_pages), | |
| 472 PagesToMiB(total_returned)); | |
| 473 } | |
| 474 } | 363 } |
| 475 | |
| 476 uint64_t n_pages = 0; | |
| 477 uint64_t r_pages = 0; | |
| 478 int n_spans = 0; | |
| 479 int r_spans = 0; | |
| 480 out->printf("Normal large spans:\n"); | |
| 481 for (Span* s = large_.normal.next; s != &large_.normal; s = s->next) { | |
| 482 out->printf(" [ %6" PRIuPTR " pages ] %6.1f MiB\n", | |
| 483 s->length, PagesToMiB(s->length)); | |
| 484 n_pages += s->length; | |
| 485 n_spans++; | |
| 486 } | |
| 487 out->printf("Unmapped large spans:\n"); | |
| 488 for (Span* s = large_.returned.next; s != &large_.returned; s = s->next) { | |
| 489 out->printf(" [ %6" PRIuPTR " pages ] %6.1f MiB\n", | |
| 490 s->length, PagesToMiB(s->length)); | |
| 491 r_pages += s->length; | |
| 492 r_spans++; | |
| 493 } | |
| 494 total_normal += n_pages; | |
| 495 total_returned += r_pages; | |
| 496 out->printf(">255 large * %6u spans ~ %6.1f MiB; %6.1f MiB cum" | |
| 497 "; unmapped: %6.1f MiB; %6.1f MiB cum\n", | |
| 498 (n_spans + r_spans), | |
| 499 PagesToMiB(n_pages + r_pages), | |
| 500 PagesToMiB(total_normal + total_returned), | |
| 501 PagesToMiB(r_pages), | |
| 502 PagesToMiB(total_returned)); | |
| 503 } | 364 } |
| 504 | 365 |
| 505 bool PageHeap::GetNextRange(PageID start, base::MallocRange* r) { | 366 bool PageHeap::GetNextRange(PageID start, base::MallocRange* r) { |
| 506 Span* span = reinterpret_cast<Span*>(pagemap_.Next(start)); | 367 Span* span = reinterpret_cast<Span*>(pagemap_.Next(start)); |
| 507 if (span == NULL) { | 368 if (span == NULL) { |
| 508 return false; | 369 return false; |
| 509 } | 370 } |
| 510 r->address = span->start << kPageShift; | 371 r->address = span->start << kPageShift; |
| 511 r->length = span->length << kPageShift; | 372 r->length = span->length << kPageShift; |
| 512 r->fraction = 0; | 373 r->fraction = 0; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 553 ask = n; | 414 ask = n; |
| 554 ptr = TCMalloc_SystemAlloc(ask << kPageShift, &actual_size, kPageSize); | 415 ptr = TCMalloc_SystemAlloc(ask << kPageShift, &actual_size, kPageSize); |
| 555 } | 416 } |
| 556 if (ptr == NULL) return false; | 417 if (ptr == NULL) return false; |
| 557 } | 418 } |
| 558 ask = actual_size >> kPageShift; | 419 ask = actual_size >> kPageShift; |
| 559 RecordGrowth(ask << kPageShift); | 420 RecordGrowth(ask << kPageShift); |
| 560 | 421 |
| 561 uint64_t old_system_bytes = stats_.system_bytes; | 422 uint64_t old_system_bytes = stats_.system_bytes; |
| 562 stats_.system_bytes += (ask << kPageShift); | 423 stats_.system_bytes += (ask << kPageShift); |
| 563 stats_.committed_bytes += (ask << kPageShift); | |
| 564 const PageID p = reinterpret_cast<uintptr_t>(ptr) >> kPageShift; | 424 const PageID p = reinterpret_cast<uintptr_t>(ptr) >> kPageShift; |
| 565 ASSERT(p > 0); | 425 ASSERT(p > 0); |
| 566 | 426 |
| 567 // If we have already a lot of pages allocated, just pre allocate a bunch of | 427 // If we have already a lot of pages allocated, just pre allocate a bunch of |
| 568 // memory for the page map. This prevents fragmentation by pagemap metadata | 428 // memory for the page map. This prevents fragmentation by pagemap metadata |
| 569 // when a program keeps allocating and freeing large blocks. | 429 // when a program keeps allocating and freeing large blocks. |
| 570 | 430 |
| 571 if (old_system_bytes < kPageMapBigAllocationThreshold | 431 if (old_system_bytes < kPageMapBigAllocationThreshold |
| 572 && stats_.system_bytes >= kPageMapBigAllocationThreshold) { | 432 && stats_.system_bytes >= kPageMapBigAllocationThreshold) { |
| 573 pagemap_.PreallocateMoreMemory(); | 433 pagemap_.PreallocateMoreMemory(); |
| 574 } | 434 } |
| 575 | 435 |
| 576 // Make sure pagemap_ has entries for all of the new pages. | 436 // Make sure pagemap_ has entries for all of the new pages. |
| 577 // Plus ensure one before and one after so coalescing code | 437 // Plus ensure one before and one after so coalescing code |
| 578 // does not need bounds-checking. | 438 // does not need bounds-checking. |
| 579 if (pagemap_.Ensure(p-1, ask+2)) { | 439 if (pagemap_.Ensure(p-1, ask+2)) { |
| 580 // Pretend the new area is allocated and then Delete() it to cause | 440 // Pretend the new area is allocated and then Delete() it to cause |
| 581 // any necessary coalescing to occur. | 441 // any necessary coalescing to occur. |
| 582 Span* span = NewSpan(p, ask); | 442 Span* span = NewSpan(p, ask); |
| 583 RecordSpan(span); | 443 RecordSpan(span); |
| 584 Delete(span); | 444 Delete(span); |
| 585 ASSERT(stats_.unmapped_bytes+ stats_.committed_bytes==stats_.system_bytes); | |
| 586 ASSERT(Check()); | 445 ASSERT(Check()); |
| 587 return true; | 446 return true; |
| 588 } else { | 447 } else { |
| 589 // We could not allocate memory within "pagemap_" | 448 // We could not allocate memory within "pagemap_" |
| 590 // TODO: Once we can return memory to the system, return the new span | 449 // TODO: Once we can return memory to the system, return the new span |
| 591 return false; | 450 return false; |
| 592 } | 451 } |
| 593 } | 452 } |
| 594 | 453 |
| 595 bool PageHeap::Check() { | 454 bool PageHeap::Check() { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 615 CHECK_CONDITION(s->location == freelist); // NORMAL or RETURNED | 474 CHECK_CONDITION(s->location == freelist); // NORMAL or RETURNED |
| 616 CHECK_CONDITION(s->length >= min_pages); | 475 CHECK_CONDITION(s->length >= min_pages); |
| 617 CHECK_CONDITION(s->length <= max_pages); | 476 CHECK_CONDITION(s->length <= max_pages); |
| 618 CHECK_CONDITION(GetDescriptor(s->start) == s); | 477 CHECK_CONDITION(GetDescriptor(s->start) == s); |
| 619 CHECK_CONDITION(GetDescriptor(s->start+s->length-1) == s); | 478 CHECK_CONDITION(GetDescriptor(s->start+s->length-1) == s); |
| 620 } | 479 } |
| 621 return true; | 480 return true; |
| 622 } | 481 } |
| 623 | 482 |
| 624 } // namespace tcmalloc | 483 } // namespace tcmalloc |
| OLD | NEW |