fix(renderer): escalate isolate maintenance under pressure

This commit is contained in:
ldm0
2026-08-25 02:41:17 +08:00
committed by Donough Liu
parent fdba8d5ae6
commit 7020b2fc55
3 changed files with 51 additions and 14 deletions
@@ -29,9 +29,10 @@ const ACTIVE_PAGE_MODERATE_MEMORY_PRESSURE_PERIOD: Duration = Duration::from_sec
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(super) enum RendererOwnerMaintenanceAction {
/// Ask V8 to perform its moderate-memory-pressure maintenance for the
/// isolate currently attached to this Page.
ModerateMemoryPressure,
/// Ask V8 to perform memory-pressure maintenance for the isolate currently
/// attached to this Page. The isolate selects moderate or critical
/// pressure from its current heap occupancy.
MemoryPressure,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
@@ -102,7 +103,7 @@ impl RendererPageOwnerMaintenanceResidence {
};
Some(RendererOwnerMaintenanceTask {
token,
action: RendererOwnerMaintenanceAction::ModerateMemoryPressure,
action: RendererOwnerMaintenanceAction::MemoryPressure,
scheduled_for: deadline,
})
}
@@ -143,11 +144,11 @@ pub(super) async fn execute_owner_maintenance_task_on_local_lane(
run_entry_on_bound_owner_local_store_local_task(local_executor, entry, move |entry| {
Box::pin(async move {
match task.action() {
RendererOwnerMaintenanceAction::ModerateMemoryPressure => entry
RendererOwnerMaintenanceAction::MemoryPressure => entry
.page_vm_mut()
.vm_mut()
.renderer_document_isolate_ops()
.notify_renderer_document_isolate_moderate_memory_pressure(),
.notify_renderer_document_isolate_memory_pressure(),
}
})
})
+29 -7
View File
@@ -53,6 +53,17 @@ use url::Url;
pub(crate) type ScriptVmBootstrapError = Box<(anyhow::Error, DomHost)>;
fn renderer_document_isolate_critical_pressure_required(
used_heap_size: usize,
heap_size_limit: usize,
) -> bool {
if heap_size_limit == 0 {
return false;
}
let critical_threshold = heap_size_limit / 3 + usize::from(!heap_size_limit.is_multiple_of(3));
used_heap_size >= critical_threshold
}
#[cfg(test)]
fn expect_ready_child_frame_owner_source_future_for_test<F>(future: F) -> F::Output
where
@@ -6742,10 +6753,24 @@ impl ScriptVm {
})
}
fn notify_renderer_document_isolate_moderate_memory_pressure(&mut self) -> Result<()> {
fn notify_renderer_document_isolate_memory_pressure(&mut self) -> Result<()> {
self.renderer_document_isolate
.with_entered_renderer_document_isolate(|isolate| {
isolate.memory_pressure_notification(v8::MemoryPressureLevel::Moderate);
let stats = isolate.get_heap_statistics();
if renderer_document_isolate_critical_pressure_required(
stats.used_heap_size(),
stats.heap_size_limit(),
) {
// One renderer process can host several Page isolates. A
// target with a rapidly replaced child realm must not hit
// V8's process-fatal heap limit before its owner can close
// that target. Escalate the existing periodic maintenance
// once this isolate consumes a third of its own limit.
isolate.memory_pressure_notification(v8::MemoryPressureLevel::Critical);
isolate.low_memory_notification();
} else {
isolate.memory_pressure_notification(v8::MemoryPressureLevel::Moderate);
}
Ok(())
})
}
@@ -6821,11 +6846,8 @@ impl ScriptVmRendererDocumentIsolateOps<'_> {
self.vm.collect_renderer_document_isolate_garbage()
}
pub(super) fn notify_renderer_document_isolate_moderate_memory_pressure(
&mut self,
) -> Result<()> {
self.vm
.notify_renderer_document_isolate_moderate_memory_pressure()
pub(super) fn notify_renderer_document_isolate_memory_pressure(&mut self) -> Result<()> {
self.vm.notify_renderer_document_isolate_memory_pressure()
}
}
+15 -1
View File
@@ -5,7 +5,7 @@ use super::{
PostParseProcessingAction, PostParseRuntimeDriverStep, PostParseStageBoundary,
PostParseTaskCompletion, PostParseTaskExecutionToken, PostParseTaskInvalidationPolicy,
ReadyPostParseAction, ScriptVm, ScriptVmDefaultWorldBootstrap, StandaloneScriptVmHarness,
select_post_parse_driver_step,
renderer_document_isolate_critical_pressure_required, select_post_parse_driver_step,
};
use crate::document_runtime::{
CurrentScriptContextSpec, DeferredPageTask, DeferredPageTaskLane, DeferredPageTaskState,
@@ -5193,6 +5193,20 @@ fn dom_wrapper_expando_survives_renderer_document_isolate_garbage_collection() {
assert_eq!(retained, "retained");
}
#[test]
fn renderer_document_isolate_memory_pressure_escalates_at_one_third_of_heap_limit() {
assert!(!renderer_document_isolate_critical_pressure_required(0, 0));
assert!(!renderer_document_isolate_critical_pressure_required(
33, 100
));
assert!(renderer_document_isolate_critical_pressure_required(
34, 100
));
assert!(renderer_document_isolate_critical_pressure_required(
100, 100
));
}
#[test]
fn context_wrapper_cache_is_cleared_on_script_vm_teardown() {
let mut vm = new_parsed_test_vm(