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

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: self-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
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) {
82 CollectGarbage(kNew); 83 CollectGarbage(kNew);
Ivan Posva 2016/01/11 06:14:09 Please add a comment that the CollectGarbage(kNew)
siva 2016/01/11 18:27:47 Added a comment. If a new space collection happen
83 addr = new_space_.TryAllocate(size); 84 addr = new_space_.TryAllocate(size);
84 if (addr == 0) { 85 if (addr == 0) {
85 return AllocateOld(size, HeapPage::kData); 86 return AllocateOld(size, HeapPage::kData);
86 } 87 }
87 } 88 }
88 return addr; 89 return addr;
89 } 90 }
90 91
91 92
92 uword Heap::AllocateOld(intptr_t size, HeapPage::PageType type) { 93 uword Heap::AllocateOld(intptr_t size, HeapPage::PageType type) {
93 ASSERT(Thread::Current()->no_safepoint_scope_depth() == 0); 94 ASSERT(Thread::Current()->no_safepoint_scope_depth() == 0);
94 uword addr = old_space_.TryAllocate(size, type); 95 uword addr = old_space_.TryAllocate(size, type);
95 if (addr != 0) { 96 if (addr != 0) {
96 return addr; 97 return addr;
97 } 98 }
98 // If we are in the process of running a sweep wait for the sweeper to free 99 // If we are in the process of running a sweep wait for the sweeper to free
99 // memory. 100 // memory.
100 { 101 {
101 MonitorLocker ml(old_space_.tasks_lock()); 102 MonitorLocker ml(old_space_.tasks_lock());
102 addr = old_space_.TryAllocate(size, type); 103 addr = old_space_.TryAllocate(size, type);
103 while ((addr == 0) && (old_space_.tasks() > 0)) { 104 while ((addr == 0) && (old_space_.tasks() > 0)) {
104 ml.Wait(); 105 ml.Wait();
105 addr = old_space_.TryAllocate(size, type); 106 addr = old_space_.TryAllocate(size, type);
106 } 107 }
107 } 108 }
108 if (addr != 0) { 109 if (addr != 0) {
109 return addr; 110 return addr;
110 } 111 }
111 // All GC tasks finished without allocating successfully. Run a full GC. 112 Thread* thread = Thread::Current();
112 CollectAllGarbage(); 113 if (thread->CanCollectGarbage()) {
113 addr = old_space_.TryAllocate(size, type); 114 // All GC tasks finished without allocating successfully. Run a full GC.
114 if (addr != 0) { 115 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); 116 addr = old_space_.TryAllocate(size, type);
121 while ((addr == 0) && (old_space_.tasks() > 0)) { 117 if (addr != 0) {
122 ml.Wait(); 118 return addr;
119 }
120 // Wait for all of the concurrent tasks to finish before giving up.
121 {
122 MonitorLocker ml(old_space_.tasks_lock());
123 addr = old_space_.TryAllocate(size, type); 123 addr = old_space_.TryAllocate(size, type);
124 while ((addr == 0) && (old_space_.tasks() > 0)) {
125 ml.Wait();
126 addr = old_space_.TryAllocate(size, type);
127 }
124 } 128 }
125 } 129 if (addr != 0) {
126 if (addr != 0) { 130 return addr;
127 return addr; 131 }
128 } 132 // Force growth before attempting a synchronous GC.
Ivan Posva 2016/01/11 06:14:09 a -> another
siva 2016/01/11 18:27:47 Done.
129 // Force growth before attempting a synchronous GC. 133 addr = old_space_.TryAllocate(size, type, PageSpace::kForceGrowth);
130 addr = old_space_.TryAllocate(size, type, PageSpace::kForceGrowth); 134 if (addr != 0) {
131 if (addr != 0) { 135 return addr;
132 return addr; 136 }
133 } 137 // Before throwing an out-of-memory error try a synchronous GC.
134 // Before throwing an out-of-memory error try a synchronous GC. 138 CollectAllGarbage();
135 CollectAllGarbage(); 139 {
136 { 140 MonitorLocker ml(old_space_.tasks_lock());
137 MonitorLocker ml(old_space_.tasks_lock()); 141 while (old_space_.tasks() > 0) {
138 while (old_space_.tasks() > 0) { 142 ml.Wait();
139 ml.Wait(); 143 }
140 } 144 }
141 } 145 }
142 addr = old_space_.TryAllocate(size, type, PageSpace::kForceGrowth); 146 addr = old_space_.TryAllocate(size, type, PageSpace::kForceGrowth);
143 if (addr != 0) { 147 if (addr != 0) {
144 return addr; 148 return addr;
145 } 149 }
146 // Give up allocating this object. 150 // Give up allocating this object.
147 OS::PrintErr( 151 OS::PrintErr(
148 "Exhausted heap space, trying to allocate %" Pd " bytes.\n", size); 152 "Exhausted heap space, trying to allocate %" Pd " bytes.\n", size);
149 return 0; 153 return 0;
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
300 } 304 }
301 raw_obj = FindOldObject(visitor); 305 raw_obj = FindOldObject(visitor);
302 if (raw_obj != Object::null()) { 306 if (raw_obj != Object::null()) {
303 return raw_obj; 307 return raw_obj;
304 } 308 }
305 raw_obj = FindObjectInCodeSpace(visitor); 309 raw_obj = FindObjectInCodeSpace(visitor);
306 return raw_obj; 310 return raw_obj;
307 } 311 }
308 312
309 313
310 bool Heap::gc_in_progress() { 314 bool Heap::BeginNewSpaceGC() {
311 MutexLocker ml(&gc_in_progress_mutex_); 315 MonitorLocker ml(&gc_in_progress_monitor_);
312 return gc_in_progress_; 316 bool start_gc_on_thread = true;
317 while (gc_new_space_in_progress_ ||
318 gc_old_space_in_progress_) {
319 start_gc_on_thread = !gc_new_space_in_progress_;
320 ml.Wait();
321 }
322 if (start_gc_on_thread) {
323 gc_new_space_in_progress_ = true;
324 return true;
325 }
326 return false;
313 } 327 }
314 328
315 329
316 void Heap::BeginGC() { 330 void Heap::EndNewSpaceGC() {
317 MutexLocker ml(&gc_in_progress_mutex_); 331 MonitorLocker ml(&gc_in_progress_monitor_);
318 ASSERT(!gc_in_progress_); 332 ASSERT(gc_new_space_in_progress_);
319 gc_in_progress_ = true; 333 gc_new_space_in_progress_ = false;
334 ml.NotifyAll();
320 } 335 }
321 336
322 337
323 void Heap::EndGC() { 338 bool Heap::BeginOldSpaceGC() {
324 MutexLocker ml(&gc_in_progress_mutex_); 339 MonitorLocker ml(&gc_in_progress_monitor_);
325 ASSERT(gc_in_progress_); 340 bool start_gc_on_thread = true;
326 gc_in_progress_ = false; 341 while (gc_new_space_in_progress_ ||
342 gc_old_space_in_progress_) {
343 start_gc_on_thread = !gc_old_space_in_progress_;
344 ml.Wait();
345 }
346 if (start_gc_on_thread) {
347 gc_old_space_in_progress_ = true;
348 return true;
349 }
350 return false;
327 } 351 }
328 352
329 353
330 void Heap::CollectGarbage(Space space, 354 void Heap::EndOldSpaceGC() {
331 ApiCallbacks api_callbacks, 355 MonitorLocker ml(&gc_in_progress_monitor_);
332 GCReason reason) { 356 ASSERT(gc_old_space_in_progress_);
333 Thread* thread = Thread::Current(); 357 gc_old_space_in_progress_ = false;
334 bool invoke_api_callbacks = (api_callbacks == kInvokeApiCallbacks); 358 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 } 359 }
371 360
372 361
373 void Heap::UpdateClassHeapStatsBeforeGC(Heap::Space space) { 362 void Heap::UpdateClassHeapStatsBeforeGC(Heap::Space space) {
374 ClassTable* class_table = isolate()->class_table(); 363 ClassTable* class_table = isolate()->class_table();
375 if (space == kNew) { 364 if (space == kNew) {
376 class_table->ResetCountersNew(); 365 class_table->ResetCountersNew();
377 } else { 366 } else {
378 class_table->ResetCountersOld(); 367 class_table->ResetCountersOld();
379 } 368 }
380 } 369 }
381 370
382 371
372 void Heap::CollectNewSpaceGarbage(Thread* thread,
373 ApiCallbacks api_callbacks,
374 GCReason reason) {
375 if (BeginNewSpaceGC()) {
376 bool invoke_api_callbacks = (api_callbacks == kInvokeApiCallbacks);
377 RecordBeforeGC(kNew, reason);
378 VMTagScope tagScope(thread, VMTag::kGCNewSpaceTagId);
379 TimelineDurationScope tds(thread,
380 isolate()->GetGCStream(),
381 "CollectNewGeneration");
382 UpdateClassHeapStatsBeforeGC(kNew);
383 new_space_.Scavenge(invoke_api_callbacks);
384 isolate()->class_table()->UpdatePromoted();
385 UpdatePretenurePolicy();
386 RecordAfterGC(kNew);
387 PrintStats();
388 EndNewSpaceGC();
389 if (old_space_.NeedsGarbageCollection()) {
390 // Old collections should call the API callbacks.
391 CollectOldSpaceGarbage(thread, kInvokeApiCallbacks, kPromotion);
392 }
393 }
394 }
395
396
397 void Heap::CollectOldSpaceGarbage(Thread* thread,
398 ApiCallbacks api_callbacks,
399 GCReason reason) {
400 if (BeginOldSpaceGC()) {
401 bool invoke_api_callbacks = (api_callbacks == kInvokeApiCallbacks);
402 RecordBeforeGC(kOld, reason);
403 VMTagScope tagScope(thread, VMTag::kGCOldSpaceTagId);
404 TimelineDurationScope tds(thread,
405 isolate()->GetGCStream(),
406 "CollectOldGeneration");
407 UpdateClassHeapStatsBeforeGC(kOld);
408 old_space_.MarkSweep(invoke_api_callbacks);
409 RecordAfterGC(kOld);
410 PrintStats();
411 EndOldSpaceGC();
412 }
413 }
414
415
416 void Heap::CollectGarbage(Space space,
417 ApiCallbacks api_callbacks,
418 GCReason reason) {
419 Thread* thread = Thread::Current();
420 switch (space) {
421 case kNew: {
422 CollectNewSpaceGarbage(thread, api_callbacks, reason);
423 break;
424 }
425 case kOld:
426 case kCode: {
427 CollectOldSpaceGarbage(thread, api_callbacks, reason);
428 break;
429 }
430 default:
431 UNREACHABLE();
432 }
433 }
434
435
383 void Heap::CollectGarbage(Space space) { 436 void Heap::CollectGarbage(Space space) {
437 Thread* thread = Thread::Current();
384 if (space == kOld) { 438 if (space == kOld) {
385 CollectGarbage(space, kInvokeApiCallbacks, kOldSpace); 439 CollectOldSpaceGarbage(thread, kInvokeApiCallbacks, kOldSpace);
386 } else { 440 } else {
387 ASSERT(space == kNew); 441 ASSERT(space == kNew);
388 CollectGarbage(space, kInvokeApiCallbacks, kNewSpace); 442 CollectNewSpaceGarbage(thread, kInvokeApiCallbacks, kNewSpace);
389 } 443 }
390 } 444 }
391 445
392 446
393 void Heap::CollectAllGarbage() { 447 void Heap::CollectAllGarbage() {
394 Thread* thread = Thread::Current(); 448 Thread* thread = Thread::Current();
395 { 449 CollectNewSpaceGarbage(thread, kInvokeApiCallbacks, kFull);
396 RecordBeforeGC(kNew, kFull); 450 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 } 451 }
420 452
421 453
422 bool Heap::ShouldPretenure(intptr_t class_id) const { 454 bool Heap::ShouldPretenure(intptr_t class_id) const {
423 if (class_id == kOneByteStringCid) { 455 if (class_id == kOneByteStringCid) {
424 return pretenure_policy_ > 0; 456 return pretenure_policy_ > 0;
425 } else { 457 } else {
426 return false; 458 return false;
427 } 459 }
428 } 460 }
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after
687 void Heap::PrintToJSONObject(Space space, JSONObject* object) const { 719 void Heap::PrintToJSONObject(Space space, JSONObject* object) const {
688 if (space == kNew) { 720 if (space == kNew) {
689 new_space_.PrintToJSONObject(object); 721 new_space_.PrintToJSONObject(object);
690 } else { 722 } else {
691 old_space_.PrintToJSONObject(object); 723 old_space_.PrintToJSONObject(object);
692 } 724 }
693 } 725 }
694 726
695 727
696 void Heap::RecordBeforeGC(Space space, GCReason reason) { 728 void Heap::RecordBeforeGC(Space space, GCReason reason) {
697 BeginGC(); 729 ASSERT((space == kNew && gc_new_space_in_progress_) ||
730 (space == kOld && gc_old_space_in_progress_));
698 stats_.num_++; 731 stats_.num_++;
699 stats_.space_ = space; 732 stats_.space_ = space;
700 stats_.reason_ = reason; 733 stats_.reason_ = reason;
701 stats_.before_.micros_ = OS::GetCurrentTimeMicros(); 734 stats_.before_.micros_ = OS::GetCurrentTimeMicros();
702 stats_.before_.new_ = new_space_.GetCurrentUsage(); 735 stats_.before_.new_ = new_space_.GetCurrentUsage();
703 stats_.before_.old_ = old_space_.GetCurrentUsage(); 736 stats_.before_.old_ = old_space_.GetCurrentUsage();
704 stats_.times_[0] = 0; 737 stats_.times_[0] = 0;
705 stats_.times_[1] = 0; 738 stats_.times_[1] = 0;
706 stats_.times_[2] = 0; 739 stats_.times_[2] = 0;
707 stats_.times_[3] = 0; 740 stats_.times_[3] = 0;
708 stats_.data_[0] = 0; 741 stats_.data_[0] = 0;
709 stats_.data_[1] = 0; 742 stats_.data_[1] = 0;
710 stats_.data_[2] = 0; 743 stats_.data_[2] = 0;
711 stats_.data_[3] = 0; 744 stats_.data_[3] = 0;
712 } 745 }
713 746
714 747
715 void Heap::RecordAfterGC() { 748 void Heap::RecordAfterGC(Space space) {
716 stats_.after_.micros_ = OS::GetCurrentTimeMicros(); 749 stats_.after_.micros_ = OS::GetCurrentTimeMicros();
717 int64_t delta = stats_.after_.micros_ - stats_.before_.micros_; 750 int64_t delta = stats_.after_.micros_ - stats_.before_.micros_;
718 if (stats_.space_ == kNew) { 751 if (stats_.space_ == kNew) {
719 new_space_.AddGCTime(delta); 752 new_space_.AddGCTime(delta);
720 new_space_.IncrementCollections(); 753 new_space_.IncrementCollections();
721 } else { 754 } else {
722 old_space_.AddGCTime(delta); 755 old_space_.AddGCTime(delta);
723 old_space_.IncrementCollections(); 756 old_space_.IncrementCollections();
724 } 757 }
725 stats_.after_.new_ = new_space_.GetCurrentUsage(); 758 stats_.after_.new_ = new_space_.GetCurrentUsage();
726 stats_.after_.old_ = old_space_.GetCurrentUsage(); 759 stats_.after_.old_ = old_space_.GetCurrentUsage();
727 EndGC(); 760 ASSERT((space == kNew && gc_new_space_in_progress_) ||
761 (space == kOld && gc_old_space_in_progress_));
728 if (Service::gc_stream.enabled()) { 762 if (Service::gc_stream.enabled()) {
729 ServiceEvent event(Isolate::Current(), ServiceEvent::kGC); 763 ServiceEvent event(Isolate::Current(), ServiceEvent::kGC);
730 event.set_gc_stats(&stats_); 764 event.set_gc_stats(&stats_);
731 Service::HandleEvent(&event); 765 Service::HandleEvent(&event);
732 } 766 }
733 } 767 }
734 768
735 769
736 void Heap::PrintStats() { 770 void Heap::PrintStats() {
737 if (!FLAG_verbose_gc) return; 771 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_); 841 Dart::vm_isolate()->heap()->WriteProtect(false, include_code_pages_);
808 } 842 }
809 843
810 844
811 WritableVMIsolateScope::~WritableVMIsolateScope() { 845 WritableVMIsolateScope::~WritableVMIsolateScope() {
812 ASSERT(Dart::vm_isolate()->heap()->UsedInWords(Heap::kNew) == 0); 846 ASSERT(Dart::vm_isolate()->heap()->UsedInWords(Heap::kNew) == 0);
813 Dart::vm_isolate()->heap()->WriteProtect(true, include_code_pages_); 847 Dart::vm_isolate()->heap()->WriteProtect(true, include_code_pages_);
814 } 848 }
815 849
816 } // namespace dart 850 } // namespace dart
OLDNEW
« runtime/vm/compiler.cc ('K') | « runtime/vm/heap.h ('k') | runtime/vm/thread.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698