mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 04:57:43 +00:00
[vm, gc] Retry allocation under the safepoint before performing GC.
This avoids back-to-back GCs where multiple threads race to enter a safepoint operation to perform GC, and the losers of the race perform GC after they enter their own safepoint operation. TEST=ci Bug: https://github.com/dart-lang/sdk/issues/29415 Change-Id: Ic9be830b0c4438f9b57ea9f54464b342872175f8 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/300860 Reviewed-by: Siva Annamalai <asiva@google.com> Commit-Queue: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
parent
1bd1d9d320
commit
1c1e11b0e7
|
@ -86,9 +86,16 @@ uword Heap::AllocateNew(Thread* thread, intptr_t size) {
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
if (!assume_scavenge_will_fail_ && !thread->force_growth()) {
|
if (!assume_scavenge_will_fail_ && !thread->force_growth()) {
|
||||||
// This call to CollectGarbage might end up "reusing" a collection spawned
|
GcSafepointOperationScope safepoint_operation(thread);
|
||||||
// from a different thread and will be racing to allocate the requested
|
|
||||||
// memory with other threads being released after the collection.
|
// Another thread may have won the race to the safepoint and performed a GC
|
||||||
|
// before this thread acquired the safepoint. Retry the allocation under the
|
||||||
|
// safepoint to avoid back-to-back GC.
|
||||||
|
addr = new_space_.TryAllocate(thread, size);
|
||||||
|
if (addr != 0) {
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
CollectGarbage(thread, GCType::kScavenge, GCReason::kNewSpace);
|
CollectGarbage(thread, GCType::kScavenge, GCReason::kNewSpace);
|
||||||
|
|
||||||
addr = new_space_.TryAllocate(thread, size);
|
addr = new_space_.TryAllocate(thread, size);
|
||||||
|
@ -123,6 +130,14 @@ uword Heap::AllocateOld(Thread* thread, intptr_t size, bool is_exec) {
|
||||||
if (addr != 0) {
|
if (addr != 0) {
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
GcSafepointOperationScope safepoint_operation(thread);
|
||||||
|
// Another thread may have won the race to the safepoint and performed a GC
|
||||||
|
// before this thread acquired the safepoint. Retry the allocation under the
|
||||||
|
// safepoint to avoid back-to-back GC.
|
||||||
|
addr = old_space_.TryAllocate(size, is_exec);
|
||||||
|
if (addr != 0) {
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
// All GC tasks finished without allocating successfully. Collect both
|
// All GC tasks finished without allocating successfully. Collect both
|
||||||
// generations.
|
// generations.
|
||||||
CollectMostGarbage(GCReason::kOldSpace, /*compact=*/false);
|
CollectMostGarbage(GCReason::kOldSpace, /*compact=*/false);
|
||||||
|
@ -131,7 +146,7 @@ uword Heap::AllocateOld(Thread* thread, intptr_t size, bool is_exec) {
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
// Wait for all of the concurrent tasks to finish before giving up.
|
// Wait for all of the concurrent tasks to finish before giving up.
|
||||||
WaitForSweeperTasks(thread);
|
WaitForSweeperTasksAtSafepoint(thread);
|
||||||
addr = old_space_.TryAllocate(size, is_exec);
|
addr = old_space_.TryAllocate(size, is_exec);
|
||||||
if (addr != 0) {
|
if (addr != 0) {
|
||||||
return addr;
|
return addr;
|
||||||
|
@ -143,7 +158,7 @@ uword Heap::AllocateOld(Thread* thread, intptr_t size, bool is_exec) {
|
||||||
}
|
}
|
||||||
// Before throwing an out-of-memory error try a synchronous GC.
|
// Before throwing an out-of-memory error try a synchronous GC.
|
||||||
CollectAllGarbage(GCReason::kOldSpace, /*compact=*/true);
|
CollectAllGarbage(GCReason::kOldSpace, /*compact=*/true);
|
||||||
WaitForSweeperTasks(thread);
|
WaitForSweeperTasksAtSafepoint(thread);
|
||||||
}
|
}
|
||||||
uword addr = old_space_.TryAllocate(size, is_exec, PageSpace::kForceGrowth);
|
uword addr = old_space_.TryAllocate(size, is_exec, PageSpace::kForceGrowth);
|
||||||
if (addr != 0) {
|
if (addr != 0) {
|
||||||
|
@ -573,7 +588,6 @@ void Heap::CollectAllGarbage(GCReason reason, bool compact) {
|
||||||
}
|
}
|
||||||
CollectOldSpaceGarbage(
|
CollectOldSpaceGarbage(
|
||||||
thread, compact ? GCType::kMarkCompact : GCType::kMarkSweep, reason);
|
thread, compact ? GCType::kMarkCompact : GCType::kMarkSweep, reason);
|
||||||
WaitForSweeperTasks(thread);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Heap::CheckCatchUp(Thread* thread) {
|
void Heap::CheckCatchUp(Thread* thread) {
|
||||||
|
|
Loading…
Reference in a new issue