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

Side by Side Diff: runtime/vm/heap.cc

Issue 1562853003: 1. Add code to grow the heap instead of collecting garbage in Heap::AllocateOld when allocation is … (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: address-code-review-comments Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/vm/heap.h ('k') | runtime/vm/thread.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/heap.h" 5 #include "vm/heap.h"
6 6
7 #include "platform/assert.h" 7 #include "platform/assert.h"
8 #include "platform/utils.h" 8 #include "platform/utils.h"
9 #include "vm/flags.h" 9 #include "vm/flags.h"
10 #include "vm/isolate.h" 10 #include "vm/isolate.h"
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
44 44
45 45
46 Heap::Heap(Isolate* isolate, 46 Heap::Heap(Isolate* isolate,
47 intptr_t max_new_gen_semi_words, 47 intptr_t max_new_gen_semi_words,
48 intptr_t max_old_gen_words, 48 intptr_t max_old_gen_words,
49 intptr_t max_external_words) 49 intptr_t max_external_words)
50 : isolate_(isolate), 50 : isolate_(isolate),
51 new_space_(this, max_new_gen_semi_words, kNewObjectAlignmentOffset), 51 new_space_(this, max_new_gen_semi_words, kNewObjectAlignmentOffset),
52 old_space_(this, max_old_gen_words, max_external_words), 52 old_space_(this, max_old_gen_words, max_external_words),
53 read_only_(false), 53 read_only_(false),
54 gc_in_progress_(false), 54 gc_new_space_in_progress_(false),
55 gc_old_space_in_progress_(false),
55 pretenure_policy_(0) { 56 pretenure_policy_(0) {
56 for (int sel = 0; 57 for (int sel = 0;
57 sel < kNumWeakSelectors; 58 sel < kNumWeakSelectors;
58 sel++) { 59 sel++) {
59 new_weak_tables_[sel] = new WeakTable(); 60 new_weak_tables_[sel] = new WeakTable();
60 old_weak_tables_[sel] = new WeakTable(); 61 old_weak_tables_[sel] = new WeakTable();
61 } 62 }
62 stats_.num_ = 0; 63 stats_.num_ = 0;
63 } 64 }
64 65
65 66
66 Heap::~Heap() { 67 Heap::~Heap() {
67 for (int sel = 0; 68 for (int sel = 0;
68 sel < kNumWeakSelectors; 69 sel < kNumWeakSelectors;
69 sel++) { 70 sel++) {
70 delete new_weak_tables_[sel]; 71 delete new_weak_tables_[sel];
71 delete old_weak_tables_[sel]; 72 delete old_weak_tables_[sel];
72 } 73 }
73 } 74 }
74 75
75 76
76 uword Heap::AllocateNew(intptr_t size) { 77 uword Heap::AllocateNew(intptr_t size) {
77 ASSERT(Thread::Current()->no_safepoint_scope_depth() == 0); 78 ASSERT(Thread::Current()->no_safepoint_scope_depth() == 0);
78 // Currently, only the Dart thread may allocate in new space. 79 // Currently, only the Dart thread may allocate in new space.
79 isolate()->AssertCurrentThreadIsMutator(); 80 isolate()->AssertCurrentThreadIsMutator();
80 uword addr = new_space_.TryAllocate(size); 81 uword addr = new_space_.TryAllocate(size);
81 if (addr == 0) { 82 if (addr == 0) {
83 // This call to CollectGarbage might end up "reusing" a collection spawned
84 // from a different thread and will be racing to allocate the requested
85 // memory with other threads being released after the collection.
82 CollectGarbage(kNew); 86 CollectGarbage(kNew);
83 addr = new_space_.TryAllocate(size); 87 addr = new_space_.TryAllocate(size);
84 if (addr == 0) { 88 if (addr == 0) {
85 return AllocateOld(size, HeapPage::kData); 89 return AllocateOld(size, HeapPage::kData);
86 } 90 }
87 } 91 }
88 return addr; 92 return addr;
89 } 93 }
90 94
91 95
92 uword Heap::AllocateOld(intptr_t size, HeapPage::PageType type) { 96 uword Heap::AllocateOld(intptr_t size, HeapPage::PageType type) {
93 ASSERT(Thread::Current()->no_safepoint_scope_depth() == 0); 97 ASSERT(Thread::Current()->no_safepoint_scope_depth() == 0);
94 uword addr = old_space_.TryAllocate(size, type); 98 uword addr = old_space_.TryAllocate(size, type);
95 if (addr != 0) { 99 if (addr != 0) {
96 return addr; 100 return addr;
97 } 101 }
98 // If we are in the process of running a sweep wait for the sweeper to free 102 // If we are in the process of running a sweep wait for the sweeper to free
99 // memory. 103 // memory.
100 { 104 {
101 MonitorLocker ml(old_space_.tasks_lock()); 105 MonitorLocker ml(old_space_.tasks_lock());
102 addr = old_space_.TryAllocate(size, type); 106 addr = old_space_.TryAllocate(size, type);
103 while ((addr == 0) && (old_space_.tasks() > 0)) { 107 while ((addr == 0) && (old_space_.tasks() > 0)) {
104 ml.Wait(); 108 ml.Wait();
105 addr = old_space_.TryAllocate(size, type); 109 addr = old_space_.TryAllocate(size, type);
106 } 110 }
107 } 111 }
108 if (addr != 0) { 112 if (addr != 0) {
109 return addr; 113 return addr;
110 } 114 }
111 // All GC tasks finished without allocating successfully. Run a full GC. 115 Thread* thread = Thread::Current();
112 CollectAllGarbage(); 116 if (thread->CanCollectGarbage()) {
113 addr = old_space_.TryAllocate(size, type); 117 // All GC tasks finished without allocating successfully. Run a full GC.
114 if (addr != 0) { 118 CollectAllGarbage();
115 return addr;
116 }
117 // Wait for all of the concurrent tasks to finish before giving up.
118 {
119 MonitorLocker ml(old_space_.tasks_lock());
120 addr = old_space_.TryAllocate(size, type); 119 addr = old_space_.TryAllocate(size, type);
121 while ((addr == 0) && (old_space_.tasks() > 0)) { 120 if (addr != 0) {
122 ml.Wait(); 121 return addr;
122 }
123 // Wait for all of the concurrent tasks to finish before giving up.
124 {
125 MonitorLocker ml(old_space_.tasks_lock());
123 addr = old_space_.TryAllocate(size, type); 126 addr = old_space_.TryAllocate(size, type);
127 while ((addr == 0) && (old_space_.tasks() > 0)) {
128 ml.Wait();
129 addr = old_space_.TryAllocate(size, type);
130 }
124 } 131 }
125 } 132 if (addr != 0) {
126 if (addr != 0) { 133 return addr;
127 return addr; 134 }
128 } 135 // Force growth before attempting another synchronous GC.
129 // Force growth before attempting a synchronous GC. 136 addr = old_space_.TryAllocate(size, type, PageSpace::kForceGrowth);
130 addr = old_space_.TryAllocate(size, type, PageSpace::kForceGrowth); 137 if (addr != 0) {
131 if (addr != 0) { 138 return addr;
132 return addr; 139 }
133 } 140 // Before throwing an out-of-memory error try a synchronous GC.
134 // Before throwing an out-of-memory error try a synchronous GC. 141 CollectAllGarbage();
135 CollectAllGarbage(); 142 {
136 { 143 MonitorLocker ml(old_space_.tasks_lock());
137 MonitorLocker ml(old_space_.tasks_lock()); 144 while (old_space_.tasks() > 0) {
138 while (old_space_.tasks() > 0) { 145 ml.Wait();
139 ml.Wait(); 146 }
140 } 147 }
141 } 148 }
142 addr = old_space_.TryAllocate(size, type, PageSpace::kForceGrowth); 149 addr = old_space_.TryAllocate(size, type, PageSpace::kForceGrowth);
143 if (addr != 0) { 150 if (addr != 0) {
144 return addr; 151 return addr;
145 } 152 }
146 // Give up allocating this object. 153 // Give up allocating this object.
147 OS::PrintErr( 154 OS::PrintErr(
148 "Exhausted heap space, trying to allocate %" Pd " bytes.\n", size); 155 "Exhausted heap space, trying to allocate %" Pd " bytes.\n", size);
149 return 0; 156 return 0;
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
300 } 307 }
301 raw_obj = FindOldObject(visitor); 308 raw_obj = FindOldObject(visitor);
302 if (raw_obj != Object::null()) { 309 if (raw_obj != Object::null()) {
303 return raw_obj; 310 return raw_obj;
304 } 311 }
305 raw_obj = FindObjectInCodeSpace(visitor); 312 raw_obj = FindObjectInCodeSpace(visitor);
306 return raw_obj; 313 return raw_obj;
307 } 314 }
308 315
309 316
310 bool Heap::gc_in_progress() { 317 bool Heap::BeginNewSpaceGC() {
311 MutexLocker ml(&gc_in_progress_mutex_); 318 MonitorLocker ml(&gc_in_progress_monitor_);
312 return gc_in_progress_; 319 bool start_gc_on_thread = true;
320 while (gc_new_space_in_progress_ ||
321 gc_old_space_in_progress_) {
322 start_gc_on_thread = !gc_new_space_in_progress_;
323 ml.Wait();
324 }
325 if (start_gc_on_thread) {
326 gc_new_space_in_progress_ = true;
327 return true;
328 }
329 return false;
313 } 330 }
314 331
315 332
316 void Heap::BeginGC() { 333 void Heap::EndNewSpaceGC() {
317 MutexLocker ml(&gc_in_progress_mutex_); 334 MonitorLocker ml(&gc_in_progress_monitor_);
318 ASSERT(!gc_in_progress_); 335 ASSERT(gc_new_space_in_progress_);
319 gc_in_progress_ = true; 336 gc_new_space_in_progress_ = false;
337 ml.NotifyAll();
320 } 338 }
321 339
322 340
323 void Heap::EndGC() { 341 bool Heap::BeginOldSpaceGC() {
324 MutexLocker ml(&gc_in_progress_mutex_); 342 MonitorLocker ml(&gc_in_progress_monitor_);
325 ASSERT(gc_in_progress_); 343 bool start_gc_on_thread = true;
326 gc_in_progress_ = false; 344 while (gc_new_space_in_progress_ ||
345 gc_old_space_in_progress_) {
346 start_gc_on_thread = !gc_old_space_in_progress_;
347 ml.Wait();
348 }
349 if (start_gc_on_thread) {
350 gc_old_space_in_progress_ = true;
351 return true;
352 }
353 return false;
327 } 354 }
328 355
329 356
330 void Heap::CollectGarbage(Space space, 357 void Heap::EndOldSpaceGC() {
331 ApiCallbacks api_callbacks, 358 MonitorLocker ml(&gc_in_progress_monitor_);
332 GCReason reason) { 359 ASSERT(gc_old_space_in_progress_);
333 Thread* thread = Thread::Current(); 360 gc_old_space_in_progress_ = false;
334 bool invoke_api_callbacks = (api_callbacks == kInvokeApiCallbacks); 361 ml.NotifyAll();
335 switch (space) {
336 case kNew: {
337 RecordBeforeGC(kNew, reason);
338 VMTagScope tagScope(thread, VMTag::kGCNewSpaceTagId);
339 TimelineDurationScope tds(thread,
340 isolate()->GetGCStream(),
341 "CollectNewGeneration");
342 UpdateClassHeapStatsBeforeGC(kNew);
343 new_space_.Scavenge(invoke_api_callbacks);
344 isolate()->class_table()->UpdatePromoted();
345 UpdatePretenurePolicy();
346 RecordAfterGC();
347 PrintStats();
348 if (old_space_.NeedsGarbageCollection()) {
349 // Old collections should call the API callbacks.
350 CollectGarbage(kOld, kInvokeApiCallbacks, kPromotion);
351 }
352 break;
353 }
354 case kOld:
355 case kCode: {
356 RecordBeforeGC(kOld, reason);
357 VMTagScope tagScope(thread, VMTag::kGCOldSpaceTagId);
358 TimelineDurationScope tds(thread,
359 isolate()->GetGCStream(),
360 "CollectOldGeneration");
361 UpdateClassHeapStatsBeforeGC(kOld);
362 old_space_.MarkSweep(invoke_api_callbacks);
363 RecordAfterGC();
364 PrintStats();
365 break;
366 }
367 default:
368 UNREACHABLE();
369 }
370 } 362 }
371 363
372 364
373 void Heap::UpdateClassHeapStatsBeforeGC(Heap::Space space) { 365 void Heap::UpdateClassHeapStatsBeforeGC(Heap::Space space) {
374 ClassTable* class_table = isolate()->class_table(); 366 ClassTable* class_table = isolate()->class_table();
375 if (space == kNew) { 367 if (space == kNew) {
376 class_table->ResetCountersNew(); 368 class_table->ResetCountersNew();
377 } else { 369 } else {
378 class_table->ResetCountersOld(); 370 class_table->ResetCountersOld();
379 } 371 }
380 } 372 }
381 373
382 374
375 void Heap::CollectNewSpaceGarbage(Thread* thread,
376 ApiCallbacks api_callbacks,
377 GCReason reason) {
378 if (BeginNewSpaceGC()) {
379 bool invoke_api_callbacks = (api_callbacks == kInvokeApiCallbacks);
380 RecordBeforeGC(kNew, reason);
381 VMTagScope tagScope(thread, VMTag::kGCNewSpaceTagId);
382 TimelineDurationScope tds(thread,
383 isolate()->GetGCStream(),
384 "CollectNewGeneration");
385 UpdateClassHeapStatsBeforeGC(kNew);
386 new_space_.Scavenge(invoke_api_callbacks);
387 isolate()->class_table()->UpdatePromoted();
388 UpdatePretenurePolicy();
389 RecordAfterGC(kNew);
390 PrintStats();
391 EndNewSpaceGC();
392 if (old_space_.NeedsGarbageCollection()) {
393 // Old collections should call the API callbacks.
394 CollectOldSpaceGarbage(thread, kInvokeApiCallbacks, kPromotion);
395 }
396 }
397 }
398
399
400 void Heap::CollectOldSpaceGarbage(Thread* thread,
401 ApiCallbacks api_callbacks,
402 GCReason reason) {
403 if (BeginOldSpaceGC()) {
404 bool invoke_api_callbacks = (api_callbacks == kInvokeApiCallbacks);
405 RecordBeforeGC(kOld, reason);
406 VMTagScope tagScope(thread, VMTag::kGCOldSpaceTagId);
407 TimelineDurationScope tds(thread,
408 isolate()->GetGCStream(),
409 "CollectOldGeneration");
410 UpdateClassHeapStatsBeforeGC(kOld);
411 old_space_.MarkSweep(invoke_api_callbacks);
412 RecordAfterGC(kOld);
413 PrintStats();
414 EndOldSpaceGC();
415 }
416 }
417
418
419 void Heap::CollectGarbage(Space space,
420 ApiCallbacks api_callbacks,
421 GCReason reason) {
422 Thread* thread = Thread::Current();
423 switch (space) {
424 case kNew: {
425 CollectNewSpaceGarbage(thread, api_callbacks, reason);
426 break;
427 }
428 case kOld:
429 case kCode: {
430 CollectOldSpaceGarbage(thread, api_callbacks, reason);
431 break;
432 }
433 default:
434 UNREACHABLE();
435 }
436 }
437
438
383 void Heap::CollectGarbage(Space space) { 439 void Heap::CollectGarbage(Space space) {
440 Thread* thread = Thread::Current();
384 if (space == kOld) { 441 if (space == kOld) {
385 CollectGarbage(space, kInvokeApiCallbacks, kOldSpace); 442 CollectOldSpaceGarbage(thread, kInvokeApiCallbacks, kOldSpace);
386 } else { 443 } else {
387 ASSERT(space == kNew); 444 ASSERT(space == kNew);
388 CollectGarbage(space, kInvokeApiCallbacks, kNewSpace); 445 CollectNewSpaceGarbage(thread, kInvokeApiCallbacks, kNewSpace);
389 } 446 }
390 } 447 }
391 448
392 449
393 void Heap::CollectAllGarbage() { 450 void Heap::CollectAllGarbage() {
394 Thread* thread = Thread::Current(); 451 Thread* thread = Thread::Current();
395 { 452 CollectNewSpaceGarbage(thread, kInvokeApiCallbacks, kFull);
396 RecordBeforeGC(kNew, kFull); 453 CollectOldSpaceGarbage(thread, kInvokeApiCallbacks, kFull);
397 VMTagScope tagScope(thread, VMTag::kGCNewSpaceTagId);
398 TimelineDurationScope tds(thread,
399 isolate()->GetGCStream(),
400 "CollectNewGeneration");
401 UpdateClassHeapStatsBeforeGC(kNew);
402 new_space_.Scavenge(kInvokeApiCallbacks);
403 isolate()->class_table()->UpdatePromoted();
404 UpdatePretenurePolicy();
405 RecordAfterGC();
406 PrintStats();
407 }
408 {
409 RecordBeforeGC(kOld, kFull);
410 VMTagScope tagScope(thread, VMTag::kGCOldSpaceTagId);
411 TimelineDurationScope tds(thread,
412 isolate()->GetGCStream(),
413 "CollectOldGeneration");
414 UpdateClassHeapStatsBeforeGC(kOld);
415 old_space_.MarkSweep(kInvokeApiCallbacks);
416 RecordAfterGC();
417 PrintStats();
418 }
419 } 454 }
420 455
421 456
422 bool Heap::ShouldPretenure(intptr_t class_id) const { 457 bool Heap::ShouldPretenure(intptr_t class_id) const {
423 if (class_id == kOneByteStringCid) { 458 if (class_id == kOneByteStringCid) {
424 return pretenure_policy_ > 0; 459 return pretenure_policy_ > 0;
425 } else { 460 } else {
426 return false; 461 return false;
427 } 462 }
428 } 463 }
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after
687 void Heap::PrintToJSONObject(Space space, JSONObject* object) const { 722 void Heap::PrintToJSONObject(Space space, JSONObject* object) const {
688 if (space == kNew) { 723 if (space == kNew) {
689 new_space_.PrintToJSONObject(object); 724 new_space_.PrintToJSONObject(object);
690 } else { 725 } else {
691 old_space_.PrintToJSONObject(object); 726 old_space_.PrintToJSONObject(object);
692 } 727 }
693 } 728 }
694 729
695 730
696 void Heap::RecordBeforeGC(Space space, GCReason reason) { 731 void Heap::RecordBeforeGC(Space space, GCReason reason) {
697 BeginGC(); 732 ASSERT((space == kNew && gc_new_space_in_progress_) ||
733 (space == kOld && gc_old_space_in_progress_));
698 stats_.num_++; 734 stats_.num_++;
699 stats_.space_ = space; 735 stats_.space_ = space;
700 stats_.reason_ = reason; 736 stats_.reason_ = reason;
701 stats_.before_.micros_ = OS::GetCurrentTimeMicros(); 737 stats_.before_.micros_ = OS::GetCurrentTimeMicros();
702 stats_.before_.new_ = new_space_.GetCurrentUsage(); 738 stats_.before_.new_ = new_space_.GetCurrentUsage();
703 stats_.before_.old_ = old_space_.GetCurrentUsage(); 739 stats_.before_.old_ = old_space_.GetCurrentUsage();
704 stats_.times_[0] = 0; 740 stats_.times_[0] = 0;
705 stats_.times_[1] = 0; 741 stats_.times_[1] = 0;
706 stats_.times_[2] = 0; 742 stats_.times_[2] = 0;
707 stats_.times_[3] = 0; 743 stats_.times_[3] = 0;
708 stats_.data_[0] = 0; 744 stats_.data_[0] = 0;
709 stats_.data_[1] = 0; 745 stats_.data_[1] = 0;
710 stats_.data_[2] = 0; 746 stats_.data_[2] = 0;
711 stats_.data_[3] = 0; 747 stats_.data_[3] = 0;
712 } 748 }
713 749
714 750
715 void Heap::RecordAfterGC() { 751 void Heap::RecordAfterGC(Space space) {
716 stats_.after_.micros_ = OS::GetCurrentTimeMicros(); 752 stats_.after_.micros_ = OS::GetCurrentTimeMicros();
717 int64_t delta = stats_.after_.micros_ - stats_.before_.micros_; 753 int64_t delta = stats_.after_.micros_ - stats_.before_.micros_;
718 if (stats_.space_ == kNew) { 754 if (stats_.space_ == kNew) {
719 new_space_.AddGCTime(delta); 755 new_space_.AddGCTime(delta);
720 new_space_.IncrementCollections(); 756 new_space_.IncrementCollections();
721 } else { 757 } else {
722 old_space_.AddGCTime(delta); 758 old_space_.AddGCTime(delta);
723 old_space_.IncrementCollections(); 759 old_space_.IncrementCollections();
724 } 760 }
725 stats_.after_.new_ = new_space_.GetCurrentUsage(); 761 stats_.after_.new_ = new_space_.GetCurrentUsage();
726 stats_.after_.old_ = old_space_.GetCurrentUsage(); 762 stats_.after_.old_ = old_space_.GetCurrentUsage();
727 EndGC(); 763 ASSERT((space == kNew && gc_new_space_in_progress_) ||
764 (space == kOld && gc_old_space_in_progress_));
728 if (Service::gc_stream.enabled()) { 765 if (Service::gc_stream.enabled()) {
729 ServiceEvent event(Isolate::Current(), ServiceEvent::kGC); 766 ServiceEvent event(Isolate::Current(), ServiceEvent::kGC);
730 event.set_gc_stats(&stats_); 767 event.set_gc_stats(&stats_);
731 Service::HandleEvent(&event); 768 Service::HandleEvent(&event);
732 } 769 }
733 } 770 }
734 771
735 772
736 void Heap::PrintStats() { 773 void Heap::PrintStats() {
737 if (!FLAG_verbose_gc) return; 774 if (!FLAG_verbose_gc) return;
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
807 Dart::vm_isolate()->heap()->WriteProtect(false, include_code_pages_); 844 Dart::vm_isolate()->heap()->WriteProtect(false, include_code_pages_);
808 } 845 }
809 846
810 847
811 WritableVMIsolateScope::~WritableVMIsolateScope() { 848 WritableVMIsolateScope::~WritableVMIsolateScope() {
812 ASSERT(Dart::vm_isolate()->heap()->UsedInWords(Heap::kNew) == 0); 849 ASSERT(Dart::vm_isolate()->heap()->UsedInWords(Heap::kNew) == 0);
813 Dart::vm_isolate()->heap()->WriteProtect(true, include_code_pages_); 850 Dart::vm_isolate()->heap()->WriteProtect(true, include_code_pages_);
814 } 851 }
815 852
816 } // namespace dart 853 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/heap.h ('k') | runtime/vm/thread.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698