Index: src/heap.cc |
diff --git a/src/heap.cc b/src/heap.cc |
index ff978cf3b7f5f198165fcd01e5c82ca6b1ed3059..4c7e33d20c061f7cfdeb59eb54ee89028752fe55 100644 |
--- a/src/heap.cc |
+++ b/src/heap.cc |
@@ -236,16 +236,19 @@ int Heap::GcSafeSizeOfOldObject(HeapObject* object) { |
} |
-GarbageCollector Heap::SelectGarbageCollector(AllocationSpace space) { |
+GarbageCollector Heap::SelectGarbageCollector(AllocationSpace space, |
+ const char** reason) { |
// Is global GC requested? |
if (space != NEW_SPACE || FLAG_gc_global) { |
isolate_->counters()->gc_compactor_caused_by_request()->Increment(); |
+ *reason = "GC in old space requested"; |
return MARK_COMPACTOR; |
} |
// Is enough data promoted to justify a global GC? |
if (OldGenerationPromotionLimitReached()) { |
isolate_->counters()->gc_compactor_caused_by_promoted_data()->Increment(); |
+ *reason = "promotion limit reached"; |
return MARK_COMPACTOR; |
} |
@@ -253,6 +256,7 @@ GarbageCollector Heap::SelectGarbageCollector(AllocationSpace space) { |
if (old_gen_exhausted_) { |
isolate_->counters()-> |
gc_compactor_caused_by_oldspace_exhaustion()->Increment(); |
+ *reason = "old generations exhausted"; |
return MARK_COMPACTOR; |
} |
@@ -268,10 +272,12 @@ GarbageCollector Heap::SelectGarbageCollector(AllocationSpace space) { |
if (isolate_->memory_allocator()->MaxAvailable() <= new_space_.Size()) { |
isolate_->counters()-> |
gc_compactor_caused_by_oldspace_exhaustion()->Increment(); |
+ *reason = "scavenge might not succeed"; |
return MARK_COMPACTOR; |
} |
// Default |
+ *reason = NULL; |
return SCAVENGER; |
} |
@@ -431,17 +437,17 @@ void Heap::GarbageCollectionEpilogue() { |
} |
-void Heap::CollectAllGarbage(int flags) { |
+void Heap::CollectAllGarbage(int flags, const char* gc_reason) { |
// Since we are ignoring the return value, the exact choice of space does |
// not matter, so long as we do not specify NEW_SPACE, which would not |
// cause a full GC. |
mark_compact_collector_.SetFlags(flags); |
- CollectGarbage(OLD_POINTER_SPACE); |
+ CollectGarbage(OLD_POINTER_SPACE, gc_reason); |
mark_compact_collector_.SetFlags(kNoGCFlags); |
} |
-void Heap::CollectAllAvailableGarbage() { |
+void Heap::CollectAllAvailableGarbage(const char* gc_reason) { |
// Since we are ignoring the return value, the exact choice of space does |
// not matter, so long as we do not specify NEW_SPACE, which would not |
// cause a full GC. |
@@ -453,11 +459,12 @@ void Heap::CollectAllAvailableGarbage() { |
// Note: as weak callbacks can execute arbitrary code, we cannot |
// hope that eventually there will be no weak callbacks invocations. |
// Therefore stop recollecting after several attempts. |
- mark_compact_collector()->SetFlags(kMakeHeapIterableMask); |
+ mark_compact_collector()->SetFlags(kMakeHeapIterableMask | |
+ kReduceMemoryFootprintMask); |
isolate_->compilation_cache()->Clear(); |
const int kMaxNumberOfAttempts = 7; |
for (int attempt = 0; attempt < kMaxNumberOfAttempts; attempt++) { |
- if (!CollectGarbage(OLD_POINTER_SPACE, MARK_COMPACTOR)) { |
+ if (!CollectGarbage(OLD_POINTER_SPACE, MARK_COMPACTOR, gc_reason, NULL)) { |
break; |
} |
} |
@@ -469,7 +476,10 @@ void Heap::CollectAllAvailableGarbage() { |
} |
-bool Heap::CollectGarbage(AllocationSpace space, GarbageCollector collector) { |
+bool Heap::CollectGarbage(AllocationSpace space, |
+ GarbageCollector collector, |
+ const char* gc_reason, |
+ const char* collector_reason) { |
// The VM is in the GC state until exiting this function. |
VMState state(isolate_, GC); |
@@ -497,11 +507,12 @@ bool Heap::CollectGarbage(AllocationSpace space, GarbageCollector collector) { |
PrintF("[IncrementalMarking] Delaying MarkSweep.\n"); |
} |
collector = SCAVENGER; |
+ collector_reason = "incremental marking delaying mark-sweep"; |
} |
bool next_gc_likely_to_collect_more = false; |
- { GCTracer tracer(this); |
+ { GCTracer tracer(this, gc_reason, collector_reason); |
GarbageCollectionPrologue(); |
// The GC count was incremented in the prologue. Tell the tracer about |
// it. |
@@ -533,7 +544,7 @@ bool Heap::CollectGarbage(AllocationSpace space, GarbageCollector collector) { |
void Heap::PerformScavenge() { |
- GCTracer tracer(this); |
+ GCTracer tracer(this, NULL, NULL); |
if (incremental_marking()->IsStopped()) { |
PerformGarbageCollection(SCAVENGER, &tracer); |
} else { |
@@ -588,27 +599,33 @@ void Heap::ReserveSpace( |
while (gc_performed && counter++ < kThreshold) { |
gc_performed = false; |
if (!new_space->ReserveSpace(new_space_size)) { |
- Heap::CollectGarbage(NEW_SPACE); |
+ Heap::CollectGarbage(NEW_SPACE, |
+ "failed to reserve space in the new space"); |
gc_performed = true; |
} |
if (!old_pointer_space->ReserveSpace(pointer_space_size)) { |
- Heap::CollectGarbage(OLD_POINTER_SPACE); |
+ Heap::CollectGarbage(OLD_POINTER_SPACE, |
+ "failed to reserve space in the old pointer space"); |
gc_performed = true; |
} |
if (!(old_data_space->ReserveSpace(data_space_size))) { |
- Heap::CollectGarbage(OLD_DATA_SPACE); |
+ Heap::CollectGarbage(OLD_DATA_SPACE, |
+ "failed to reserve space in the old data space"); |
gc_performed = true; |
} |
if (!(code_space->ReserveSpace(code_space_size))) { |
- Heap::CollectGarbage(CODE_SPACE); |
+ Heap::CollectGarbage(CODE_SPACE, |
+ "failed to reserve space in the code space"); |
gc_performed = true; |
} |
if (!(map_space->ReserveSpace(map_space_size))) { |
- Heap::CollectGarbage(MAP_SPACE); |
+ Heap::CollectGarbage(MAP_SPACE, |
+ "failed to reserve space in the map space"); |
gc_performed = true; |
} |
if (!(cell_space->ReserveSpace(cell_space_size))) { |
- Heap::CollectGarbage(CELL_SPACE); |
+ Heap::CollectGarbage(CELL_SPACE, |
+ "failed to reserve space in the cell space"); |
gc_performed = true; |
} |
// We add a slack-factor of 2 in order to have space for a series of |
@@ -620,7 +637,8 @@ void Heap::ReserveSpace( |
large_object_size += cell_space_size + map_space_size + code_space_size + |
data_space_size + pointer_space_size; |
if (!(lo_space->ReserveSpace(large_object_size))) { |
- Heap::CollectGarbage(LO_SPACE); |
+ Heap::CollectGarbage(LO_SPACE, |
+ "failed to reserve space in the large object space"); |
gc_performed = true; |
} |
} |
@@ -4742,7 +4760,7 @@ bool Heap::IsHeapIterable() { |
void Heap::EnsureHeapIsIterable() { |
ASSERT(IsAllocationAllowed()); |
if (!IsHeapIterable()) { |
- CollectAllGarbage(kMakeHeapIterableMask); |
+ CollectAllGarbage(kMakeHeapIterableMask, "Heap::EnsureHeapIsIterable"); |
} |
ASSERT(IsHeapIterable()); |
} |
@@ -4812,7 +4830,7 @@ bool Heap::IdleNotification(int hint) { |
isolate_->compilation_cache()->Clear(); |
uncommit = true; |
} |
- CollectAllGarbage(kNoGCFlags); |
+ CollectAllGarbage(kNoGCFlags, "idle notification: finalize incremental"); |
gc_count_at_last_idle_gc_ = gc_count_; |
if (uncommit) { |
new_space_.Shrink(); |
@@ -4853,9 +4871,10 @@ bool Heap::IdleGlobalGC() { |
if (number_idle_notifications_ == kIdlesBeforeScavenge) { |
if (contexts_disposed_ > 0) { |
HistogramTimerScope scope(isolate_->counters()->gc_context()); |
- CollectAllGarbage(kNoGCFlags); |
+ CollectAllGarbage(kReduceMemoryFootprintMask, |
+ "idle notification: contexts disposed"); |
} else { |
- CollectGarbage(NEW_SPACE); |
+ CollectGarbage(NEW_SPACE, "idle notification"); |
} |
new_space_.Shrink(); |
last_idle_notification_gc_count_ = gc_count_; |
@@ -4865,12 +4884,12 @@ bool Heap::IdleGlobalGC() { |
// generated code for cached functions. |
isolate_->compilation_cache()->Clear(); |
- CollectAllGarbage(kNoGCFlags); |
+ CollectAllGarbage(kReduceMemoryFootprintMask, "idle notification"); |
new_space_.Shrink(); |
last_idle_notification_gc_count_ = gc_count_; |
} else if (number_idle_notifications_ == kIdlesBeforeMarkCompact) { |
- CollectAllGarbage(kNoGCFlags); |
+ CollectAllGarbage(kReduceMemoryFootprintMask, "idle notification"); |
new_space_.Shrink(); |
last_idle_notification_gc_count_ = gc_count_; |
number_idle_notifications_ = 0; |
@@ -4880,7 +4899,8 @@ bool Heap::IdleGlobalGC() { |
contexts_disposed_ = 0; |
} else { |
HistogramTimerScope scope(isolate_->counters()->gc_context()); |
- CollectAllGarbage(kNoGCFlags); |
+ CollectAllGarbage(kReduceMemoryFootprintMask, |
+ "idle notification: contexts disposed"); |
last_idle_notification_gc_count_ = gc_count_; |
} |
// If this is the first idle notification, we reset the |
@@ -6511,18 +6531,24 @@ static intptr_t CountTotalHolesSize() { |
} |
-GCTracer::GCTracer(Heap* heap) |
+GCTracer::GCTracer(Heap* heap, |
+ const char* gc_reason, |
+ const char* collector_reason) |
: start_time_(0.0), |
- start_size_(0), |
+ start_object_size_(0), |
+ start_memory_size_(0), |
gc_count_(0), |
full_gc_count_(0), |
allocated_since_last_gc_(0), |
spent_in_mutator_(0), |
promoted_objects_size_(0), |
- heap_(heap) { |
+ heap_(heap), |
+ gc_reason_(gc_reason), |
+ collector_reason_(collector_reason) { |
if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return; |
start_time_ = OS::TimeCurrentMillis(); |
- start_size_ = heap_->SizeOfObjects(); |
+ start_object_size_ = heap_->SizeOfObjects(); |
+ start_memory_size_ = heap_->isolate()->memory_allocator()->Size(); |
for (int i = 0; i < Scope::kNumberOfScopes; i++) { |
scopes_[i] = 0; |
@@ -6572,10 +6598,15 @@ GCTracer::~GCTracer() { |
if (!FLAG_trace_gc_nvp) { |
int external_time = static_cast<int>(scopes_[Scope::EXTERNAL]); |
- PrintF("%s %.1f -> %.1f MB, ", |
+ double end_memory_size_mb = |
+ static_cast<double>(heap_->isolate()->memory_allocator()->Size()) / MB; |
+ |
+ PrintF("%s %.1f (%.1f) -> %.1f (%.1f) MB, ", |
CollectorString(), |
- static_cast<double>(start_size_) / MB, |
- SizeOfHeapObjects()); |
+ static_cast<double>(start_object_size_) / MB, |
+ static_cast<double>(start_memory_size_) / MB, |
+ SizeOfHeapObjects(), |
+ end_memory_size_mb); |
if (external_time > 0) PrintF("%d / ", external_time); |
PrintF("%d ms", time); |
@@ -6592,6 +6623,15 @@ GCTracer::~GCTracer() { |
longest_step_); |
} |
} |
+ |
+ if (gc_reason_ != NULL) { |
+ PrintF(" [%s]", gc_reason_); |
+ } |
+ |
+ if (collector_reason_ != NULL) { |
+ PrintF(" [%s]", collector_reason_); |
+ } |
+ |
PrintF(".\n"); |
} else { |
PrintF("pause=%d ", time); |
@@ -6629,7 +6669,7 @@ GCTracer::~GCTracer() { |
PrintF("misc_compaction=%d ", |
static_cast<int>(scopes_[Scope::MC_UPDATE_MISC_POINTERS])); |
- PrintF("total_size_before=%" V8_PTR_PREFIX "d ", start_size_); |
+ PrintF("total_size_before=%" V8_PTR_PREFIX "d ", start_object_size_); |
PrintF("total_size_after=%" V8_PTR_PREFIX "d ", heap_->SizeOfObjects()); |
PrintF("holes_size_before=%" V8_PTR_PREFIX "d ", |
in_free_list_or_wasted_before_gc_); |