Add missing WaitForConcurrentGcToComplete calls.
Some calls to WaitForConcurrentGcToComplete were missing. This was enabling recursive GCs to occasionally occur.
Change-Id: I0dcce50ae1ebfb03681990ec3bffa7b227981383
diff --git a/src/heap.cc b/src/heap.cc
index 888c75d..0c4c6ff 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -477,6 +477,7 @@
// Fail impossible allocations
if (alloc_size > space->Capacity()) {
// On failure collect soft references
+ WaitForConcurrentGcToComplete();
CollectGarbageInternal(false, true);
return NULL;
}
@@ -504,6 +505,8 @@
++Runtime::Current()->GetStats()->gc_for_alloc_count;
++Thread::Current()->GetStats()->gc_for_alloc_count;
}
+ // We don't need a WaitForConcurrentGcToComplete here since we checked
+ // is_gc_running_ earlier and we are in a heap lock.
CollectGarbageInternal(false, false);
ptr = space->AllocWithoutGrowth(alloc_size);
if (ptr != NULL) {
@@ -529,6 +532,7 @@
// OLD-TODO: wait for the finalizers from the previous GC to finish
VLOG(gc) << "Forcing collection of SoftReferences for " << PrettySize(alloc_size) << " allocation";
+ // We don't need a WaitForConcurrentGcToComplete here either.
CollectGarbageInternal(false, true);
ptr = space->AllocWithGrowth(alloc_size);
if (ptr != NULL) {
@@ -592,7 +596,11 @@
void Heap::CollectGarbage(bool clear_soft_references) {
ScopedHeapLock heap_lock;
- CollectGarbageInternal(false, clear_soft_references);
+ // If we just waited for a GC to complete then we do not need to do another
+ // GC unless we clear soft references.
+ if (!WaitForConcurrentGcToComplete() || clear_soft_references) {
+ CollectGarbageInternal(false, clear_soft_references);
+ }
}
void Heap::CollectGarbageInternal(bool concurrent, bool clear_soft_references) {
@@ -723,7 +731,7 @@
condition_->Broadcast();
}
-void Heap::WaitForConcurrentGcToComplete() {
+bool Heap::WaitForConcurrentGcToComplete() {
lock_->AssertHeld();
// Busy wait for GC to finish
@@ -737,7 +745,10 @@
if (wait_time > MsToNs(5)) {
LOG(INFO) << "WaitForConcurrentGcToComplete blocked for " << PrettyDuration(wait_time);
}
+ DCHECK(!is_gc_running_);
+ return true;
}
+ return false;
}
void Heap::DumpForSigQuit(std::ostream& os) {
@@ -932,7 +943,10 @@
void Heap::ConcurrentGC() {
ScopedHeapLock heap_lock;
- WaitForConcurrentGcToComplete();
+ // We shouldn't need a WaitForConcurrentGcToComplete here since only
+ // concurrent GC resumes threads before the GC is completed and this function
+ // is only called within the GC daemon thread.
+ CHECK(!is_gc_running_);
// Current thread needs to be runnable or else we can't suspend all threads.
ScopedThreadStateChange tsc(Thread::Current(), kRunnable);
CollectGarbageInternal(true, false);
diff --git a/src/heap.h b/src/heap.h
index 96a9ee6..23053f5 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -120,8 +120,9 @@
// from the system. Doesn't allow the space to exceed its growth limit.
void SetIdealFootprint(size_t max_allowed_footprint);
- // Blocks the caller until the garbage collector becomes idle.
- void WaitForConcurrentGcToComplete();
+ // Blocks the caller until the garbage collector becomes idle and returns
+ // true if we waited for the GC to complete.
+ bool WaitForConcurrentGcToComplete();
pid_t GetLockOwner(); // For SignalCatcher.
void AssertLockHeld() {