mirror of
https://github.com/dart-lang/sdk
synced 2024-09-06 00:59:09 +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;
|
||||
}
|
||||
if (!assume_scavenge_will_fail_ && !thread->force_growth()) {
|
||||
// This call to CollectGarbage might end up "reusing" a collection spawned
|
||||
// from a different thread and will be racing to allocate the requested
|
||||
// memory with other threads being released after the collection.
|
||||
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 = new_space_.TryAllocate(thread, size);
|
||||
if (addr != 0) {
|
||||
return addr;
|
||||
}
|
||||
|
||||
CollectGarbage(thread, GCType::kScavenge, GCReason::kNewSpace);
|
||||
|
||||
addr = new_space_.TryAllocate(thread, size);
|
||||
|
@ -123,6 +130,14 @@ uword Heap::AllocateOld(Thread* thread, intptr_t size, bool is_exec) {
|
|||
if (addr != 0) {
|
||||
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
|
||||
// generations.
|
||||
CollectMostGarbage(GCReason::kOldSpace, /*compact=*/false);
|
||||
|
@ -131,7 +146,7 @@ uword Heap::AllocateOld(Thread* thread, intptr_t size, bool is_exec) {
|
|||
return addr;
|
||||
}
|
||||
// Wait for all of the concurrent tasks to finish before giving up.
|
||||
WaitForSweeperTasks(thread);
|
||||
WaitForSweeperTasksAtSafepoint(thread);
|
||||
addr = old_space_.TryAllocate(size, is_exec);
|
||||
if (addr != 0) {
|
||||
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.
|
||||
CollectAllGarbage(GCReason::kOldSpace, /*compact=*/true);
|
||||
WaitForSweeperTasks(thread);
|
||||
WaitForSweeperTasksAtSafepoint(thread);
|
||||
}
|
||||
uword addr = old_space_.TryAllocate(size, is_exec, PageSpace::kForceGrowth);
|
||||
if (addr != 0) {
|
||||
|
@ -573,7 +588,6 @@ void Heap::CollectAllGarbage(GCReason reason, bool compact) {
|
|||
}
|
||||
CollectOldSpaceGarbage(
|
||||
thread, compact ? GCType::kMarkCompact : GCType::kMarkSweep, reason);
|
||||
WaitForSweeperTasks(thread);
|
||||
}
|
||||
|
||||
void Heap::CheckCatchUp(Thread* thread) {
|
||||
|
|
Loading…
Reference in a new issue