heap: Fix initial GC configuration for C++-only heaps
Heaps in V8 start with a large limit that is shrunk upon young generation GCs, based on some liveness estimate. This provides best throughput during startup while at the same time finding a reasonable first limit. For C++ (embedder memory) there is no estimate which is why it was piggy-backing on V8. This breaks in scenarios where no JS memory is allocated. In this fix we start a memory reducer after embedder memory has hit the activation threshold if no GC happened so far. As soon as a single Scavenger has happened, we leave it up to the JS estimate to figure out a limit. Memory reducing GCs will then find a regular limit based on the initial live size. Drive-by: Give embedders the same activiation threshold of 8MB as JS. Bug: chromium:1217076 Change-Id: I8469696002ac2af8d75d6b47def062d2608387a1 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2944935 Reviewed-by: Dominik Inführ <dinfuehr@chromium.org> Commit-Queue: Michael Lippautz <mlippautz@chromium.org> Cr-Commit-Position: refs/heads/master@{#75012}
This commit is contained in:
parent
83d30dcb87
commit
7ef67b2e9e
@ -1927,16 +1927,28 @@ void Heap::CompleteSweepingFull() {
|
||||
void Heap::StartIncrementalMarkingIfAllocationLimitIsReached(
|
||||
int gc_flags, const GCCallbackFlags gc_callback_flags) {
|
||||
if (incremental_marking()->IsStopped()) {
|
||||
IncrementalMarkingLimit reached_limit = IncrementalMarkingLimitReached();
|
||||
if (reached_limit == IncrementalMarkingLimit::kSoftLimit) {
|
||||
incremental_marking()->incremental_marking_job()->ScheduleTask(this);
|
||||
} else if (reached_limit == IncrementalMarkingLimit::kHardLimit) {
|
||||
switch (IncrementalMarkingLimitReached()) {
|
||||
case IncrementalMarkingLimit::kHardLimit:
|
||||
StartIncrementalMarking(
|
||||
gc_flags,
|
||||
OldGenerationSpaceAvailable() <= NewSpaceCapacity()
|
||||
? GarbageCollectionReason::kAllocationLimit
|
||||
: GarbageCollectionReason::kGlobalAllocationLimit,
|
||||
gc_callback_flags);
|
||||
break;
|
||||
case IncrementalMarkingLimit::kSoftLimit:
|
||||
incremental_marking()->incremental_marking_job()->ScheduleTask(this);
|
||||
break;
|
||||
case IncrementalMarkingLimit::kFallbackForEmbedderLimit:
|
||||
// This is a fallback case where no appropriate limits have been
|
||||
// configured yet.
|
||||
MemoryReducer::Event event;
|
||||
event.type = MemoryReducer::kPossibleGarbage;
|
||||
event.time_ms = MonotonicallyIncreasingTimeInMs();
|
||||
memory_reducer()->NotifyPossibleGarbage(event);
|
||||
break;
|
||||
case IncrementalMarkingLimit::kNoLimit:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4996,12 +5008,14 @@ size_t Heap::OldGenerationSizeOfObjects() {
|
||||
return total + lo_space_->SizeOfObjects() + code_lo_space_->SizeOfObjects();
|
||||
}
|
||||
|
||||
size_t Heap::GlobalSizeOfObjects() {
|
||||
const size_t on_heap_size = OldGenerationSizeOfObjects();
|
||||
const size_t embedder_size = local_embedder_heap_tracer()
|
||||
size_t Heap::EmbedderSizeOfObjects() const {
|
||||
return local_embedder_heap_tracer()
|
||||
? local_embedder_heap_tracer()->used_size()
|
||||
: 0;
|
||||
return on_heap_size + embedder_size;
|
||||
}
|
||||
|
||||
size_t Heap::GlobalSizeOfObjects() {
|
||||
return OldGenerationSizeOfObjects() + EmbedderSizeOfObjects();
|
||||
}
|
||||
|
||||
uint64_t Heap::AllocatedExternalMemorySinceMarkCompact() {
|
||||
@ -5152,11 +5166,13 @@ double Heap::PercentToGlobalMemoryLimit() {
|
||||
return total_bytes > 0 ? (current_bytes / total_bytes) * 100.0 : 0;
|
||||
}
|
||||
|
||||
// This function returns either kNoLimit, kSoftLimit, or kHardLimit.
|
||||
// The kNoLimit means that either incremental marking is disabled or it is too
|
||||
// - kNoLimit means that either incremental marking is disabled or it is too
|
||||
// early to start incremental marking.
|
||||
// The kSoftLimit means that incremental marking should be started soon.
|
||||
// The kHardLimit means that incremental marking should be started immediately.
|
||||
// - kSoftLimit means that incremental marking should be started soon.
|
||||
// - kHardLimit means that incremental marking should be started immediately.
|
||||
// - kFallbackForEmbedderLimit means that incremental marking should be
|
||||
// started as soon as the embedder does not allocate with high throughput
|
||||
// anymore.
|
||||
Heap::IncrementalMarkingLimit Heap::IncrementalMarkingLimitReached() {
|
||||
// Code using an AlwaysAllocateScope assumes that the GC state does not
|
||||
// change; that implies that no marking steps must be performed.
|
||||
@ -5221,6 +5237,15 @@ Heap::IncrementalMarkingLimit Heap::IncrementalMarkingLimitReached() {
|
||||
if (old_generation_space_available > NewSpaceCapacity() &&
|
||||
(!global_memory_available ||
|
||||
global_memory_available > NewSpaceCapacity())) {
|
||||
if (local_embedder_heap_tracer()->InUse() &&
|
||||
!old_generation_size_configured_ && gc_count_ == 0) {
|
||||
// At this point the embedder memory is above the activation
|
||||
// threshold. No GC happened so far and it's thus unlikely to get a
|
||||
// configured heap any time soon. Start a memory reducer in this case
|
||||
// which will wait until the allocation rate is low to trigger garbage
|
||||
// collection.
|
||||
return IncrementalMarkingLimit::kFallbackForEmbedderLimit;
|
||||
}
|
||||
return IncrementalMarkingLimit::kNoLimit;
|
||||
}
|
||||
if (ShouldOptimizeForMemoryUsage()) {
|
||||
|
@ -1440,6 +1440,10 @@ class Heap {
|
||||
// Excludes external memory held by those objects.
|
||||
V8_EXPORT_PRIVATE size_t OldGenerationSizeOfObjects();
|
||||
|
||||
// Returns the size of objects held by the EmbedderHeapTracer.
|
||||
V8_EXPORT_PRIVATE size_t EmbedderSizeOfObjects() const;
|
||||
|
||||
// Returns the global size of objects (embedder + V8 non-new spaces).
|
||||
V8_EXPORT_PRIVATE size_t GlobalSizeOfObjects();
|
||||
|
||||
// We allow incremental marking to overshoot the V8 and global allocation
|
||||
@ -2016,7 +2020,12 @@ class Heap {
|
||||
|
||||
double PercentToOldGenerationLimit();
|
||||
double PercentToGlobalMemoryLimit();
|
||||
enum class IncrementalMarkingLimit { kNoLimit, kSoftLimit, kHardLimit };
|
||||
enum class IncrementalMarkingLimit {
|
||||
kNoLimit,
|
||||
kSoftLimit,
|
||||
kHardLimit,
|
||||
kFallbackForEmbedderLimit
|
||||
};
|
||||
IncrementalMarkingLimit IncrementalMarkingLimitReached();
|
||||
|
||||
bool ShouldStressCompaction() const;
|
||||
|
@ -151,7 +151,7 @@ bool IncrementalMarking::CanBeActivated() {
|
||||
|
||||
bool IncrementalMarking::IsBelowActivationThresholds() const {
|
||||
return heap_->OldGenerationSizeOfObjects() <= kV8ActivationThreshold &&
|
||||
heap_->GlobalSizeOfObjects() <= kGlobalActivationThreshold;
|
||||
heap_->EmbedderSizeOfObjects() <= kEmbedderActivationThreshold;
|
||||
}
|
||||
|
||||
void IncrementalMarking::Start(GarbageCollectionReason gc_reason) {
|
||||
|
@ -75,10 +75,10 @@ class V8_EXPORT_PRIVATE IncrementalMarking final {
|
||||
|
||||
#ifndef DEBUG
|
||||
static constexpr size_t kV8ActivationThreshold = 8 * MB;
|
||||
static constexpr size_t kGlobalActivationThreshold = 16 * MB;
|
||||
static constexpr size_t kEmbedderActivationThreshold = 8 * MB;
|
||||
#else
|
||||
static constexpr size_t kV8ActivationThreshold = 0;
|
||||
static constexpr size_t kGlobalActivationThreshold = 0;
|
||||
static constexpr size_t kEmbedderActivationThreshold = 0;
|
||||
#endif
|
||||
|
||||
#ifdef V8_ATOMIC_MARKING_STATE
|
||||
|
Loading…
Reference in New Issue
Block a user