From c3ba83ff93d7d0d4134e8b23b690cc2391d1ad85 Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Tue, 27 Jan 2026 09:39:08 +0100 Subject: [PATCH 1/2] use less aggressive v8 GC Isolate.lowMemoryNotification runs an aggrissive GC. Using Isolate.memoryPressureNotification allow a more granular control of GC. --- src/browser/Browser.zig | 2 +- src/browser/Page.zig | 9 ++++----- src/browser/js/Env.zig | 18 ++++++++++++++++++ src/browser/js/Isolate.zig | 10 ++++++++++ 4 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/browser/Browser.zig b/src/browser/Browser.zig index 70b04429..1d514a12 100644 --- a/src/browser/Browser.zig +++ b/src/browser/Browser.zig @@ -100,7 +100,7 @@ pub fn closeSession(self: *Browser) void { session.deinit(); self.session = null; _ = self.session_arena.reset(.{ .retain_with_limit = 1 * 1024 * 1024 }); - self.env.lowMemoryNotification(); + self.env.memoryPressureNotification(.critical); } } diff --git a/src/browser/Page.zig b/src/browser/Page.zig index 0cdd177f..1c8cd701 100644 --- a/src/browser/Page.zig +++ b/src/browser/Page.zig @@ -253,7 +253,7 @@ fn reset(self: *Page, comptime initializing: bool) !void { } if (comptime initializing == false) { - // Removins the context triggers the linked inspector. + // Removing the context triggers the linked inspector. // It seems to append a collect task to the message loop. self._session.executor.removeContext(); @@ -262,10 +262,9 @@ fn reset(self: *Page, comptime initializing: bool) !void { // will run after the GC and we will use memory after free. self._session.browser.runMessageLoop(); - // We force a garbage collection with lowMemoryNotification between - // page navigations to keep v8 memory usage as low as possible. - // Calling immediately after a runMessageLoop ensure - self._session.browser.env.lowMemoryNotification(); + // We force a garbage collection between page navigations to keep v8 + // memory usage as low as possible. + self._session.browser.env.memoryPressureNotification(.moderate); self._script_manager.shutdown = true; self._session.browser.http_client.abort(); diff --git a/src/browser/js/Env.zig b/src/browser/js/Env.zig index 78fde66a..69f7cd20 100644 --- a/src/browser/js/Env.zig +++ b/src/browser/js/Env.zig @@ -24,6 +24,7 @@ const log = @import("../../log.zig"); const bridge = @import("bridge.zig"); const Context = @import("Context.zig"); +const Isolate = @import("Isolate.zig"); const Platform = @import("Platform.zig"); const Snapshot = @import("Snapshot.zig"); const Inspector = @import("Inspector.zig"); @@ -193,6 +194,8 @@ pub fn newExecutionWorld(self: *Env) !ExecutionWorld { // a Context, it's managed by the garbage collector. We use the // `lowMemoryNotification` call on the isolate to encourage v8 to free // any contexts which have been freed. +// This GC is very aggressive. Use memoryPressureNotification for less +// aggressive GC passes. pub fn lowMemoryNotification(self: *Env) void { var handle_scope: js.HandleScope = undefined; handle_scope.init(self.isolate); @@ -200,6 +203,21 @@ pub fn lowMemoryNotification(self: *Env) void { self.isolate.lowMemoryNotification(); } +// V8 doesn't immediately free memory associated with +// a Context, it's managed by the garbage collector. We use the +// `memoryPressureNotification` call on the isolate to encourage v8 to free +// any contexts which have been freed. +// The level indicates the aggressivity of the GC required: +// moderate speeds up incremental GC +// critical runs one full GC +// For a more aggressive GC, use lowMemoryNotification. +pub fn memoryPressureNotification(self: *Env, level: Isolate.MemoryPressureLevel) void { + var handle_scope: js.HandleScope = undefined; + handle_scope.init(self.isolate); + defer handle_scope.deinit(); + self.isolate.memoryPressureNotification(level); +} + pub fn dumpMemoryStats(self: *Env) void { const stats = self.isolate.getHeapStatistics(); std.debug.print( diff --git a/src/browser/js/Isolate.zig b/src/browser/js/Isolate.zig index fdede915..74974cc0 100644 --- a/src/browser/js/Isolate.zig +++ b/src/browser/js/Isolate.zig @@ -57,6 +57,16 @@ pub fn lowMemoryNotification(self: Isolate) void { v8.v8__Isolate__LowMemoryNotification(self.handle); } +pub const MemoryPressureLevel = enum(u32) { + none = v8.kNone, + moderate = v8.kModerate, + critical = v8.kCritical, +}; + +pub fn memoryPressureNotification(self: Isolate, level: MemoryPressureLevel) void { + v8.v8__Isolate__MemoryPressureNotification(self.handle, @intFromEnum(level)); +} + pub fn notifyContextDisposed(self: Isolate) void { _ = v8.v8__Isolate__ContextDisposedNotification(self.handle); } From 7eb026cc0d7ed23cda3c24cc7512932a98520a29 Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Wed, 28 Jan 2026 10:38:04 +0100 Subject: [PATCH 2/2] update zig-v8 deps --- .github/actions/install/action.yml | 2 +- Dockerfile | 2 +- build.zig.zon | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/actions/install/action.yml b/.github/actions/install/action.yml index 9e4b8e38..a4567fae 100644 --- a/.github/actions/install/action.yml +++ b/.github/actions/install/action.yml @@ -13,7 +13,7 @@ inputs: zig-v8: description: 'zig v8 version to install' required: false - default: 'v0.2.5' + default: 'v0.2.6' v8: description: 'v8 version to install' required: false diff --git a/Dockerfile b/Dockerfile index 5ee73356..d2b9bf57 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ FROM debian:stable-slim ARG MINISIG=0.12 ARG ZIG_MINISIG=RWSGOq2NVecA2UPNdBUZykf1CCb147pkmdtYxgb3Ti+JO/wCYvhbAb/U ARG V8=14.0.365.4 -ARG ZIG_V8=v0.2.5 +ARG ZIG_V8=v0.2.6 ARG TARGETPLATFORM RUN apt-get update -yq && \ diff --git a/build.zig.zon b/build.zig.zon index 92506e1f..f32868b8 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -6,8 +6,8 @@ .minimum_zig_version = "0.15.2", .dependencies = .{ .v8 = .{ - .url = "https://github.com/lightpanda-io/zig-v8-fork/archive/v0.2.5.tar.gz", - .hash = "v8-0.0.0-xddH641NBAC3MqKV44YCkwvnUenhQyGlgJI8OScx0tlP", + .url = "https://github.com/lightpanda-io/zig-v8-fork/archive/v0.2.6.tar.gz", + .hash = "v8-0.0.0-xddH60NRBAAWmpZq9nWdfFAEqVJ9zqJnvr1Nl9m2AbcY", }, //.v8 = .{ .path = "../zig-v8-fork" }, .@"boringssl-zig" = .{