Merge pull request #1418 from lightpanda-io/mem-pressure

use less aggressive v8 GC
This commit is contained in:
Pierre Tachoire
2026-01-28 11:09:45 +01:00
committed by GitHub
7 changed files with 37 additions and 10 deletions

View File

@@ -13,7 +13,7 @@ inputs:
zig-v8: zig-v8:
description: 'zig v8 version to install' description: 'zig v8 version to install'
required: false required: false
default: 'v0.2.5' default: 'v0.2.6'
v8: v8:
description: 'v8 version to install' description: 'v8 version to install'
required: false required: false

View File

@@ -3,7 +3,7 @@ FROM debian:stable-slim
ARG MINISIG=0.12 ARG MINISIG=0.12
ARG ZIG_MINISIG=RWSGOq2NVecA2UPNdBUZykf1CCb147pkmdtYxgb3Ti+JO/wCYvhbAb/U ARG ZIG_MINISIG=RWSGOq2NVecA2UPNdBUZykf1CCb147pkmdtYxgb3Ti+JO/wCYvhbAb/U
ARG V8=14.0.365.4 ARG V8=14.0.365.4
ARG ZIG_V8=v0.2.5 ARG ZIG_V8=v0.2.6
ARG TARGETPLATFORM ARG TARGETPLATFORM
RUN apt-get update -yq && \ RUN apt-get update -yq && \

View File

@@ -6,8 +6,8 @@
.minimum_zig_version = "0.15.2", .minimum_zig_version = "0.15.2",
.dependencies = .{ .dependencies = .{
.v8 = .{ .v8 = .{
.url = "https://github.com/lightpanda-io/zig-v8-fork/archive/v0.2.5.tar.gz", .url = "https://github.com/lightpanda-io/zig-v8-fork/archive/v0.2.6.tar.gz",
.hash = "v8-0.0.0-xddH641NBAC3MqKV44YCkwvnUenhQyGlgJI8OScx0tlP", .hash = "v8-0.0.0-xddH60NRBAAWmpZq9nWdfFAEqVJ9zqJnvr1Nl9m2AbcY",
}, },
//.v8 = .{ .path = "../zig-v8-fork" }, //.v8 = .{ .path = "../zig-v8-fork" },
.@"boringssl-zig" = .{ .@"boringssl-zig" = .{

View File

@@ -100,7 +100,7 @@ pub fn closeSession(self: *Browser) void {
session.deinit(); session.deinit();
self.session = null; self.session = null;
_ = self.session_arena.reset(.{ .retain_with_limit = 1 * 1024 * 1024 }); _ = self.session_arena.reset(.{ .retain_with_limit = 1 * 1024 * 1024 });
self.env.lowMemoryNotification(); self.env.memoryPressureNotification(.critical);
} }
} }

View File

@@ -253,7 +253,7 @@ fn reset(self: *Page, comptime initializing: bool) !void {
} }
if (comptime initializing == false) { 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. // It seems to append a collect task to the message loop.
self._session.executor.removeContext(); 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. // will run after the GC and we will use memory after free.
self._session.browser.runMessageLoop(); self._session.browser.runMessageLoop();
// We force a garbage collection with lowMemoryNotification between // We force a garbage collection between page navigations to keep v8
// page navigations to keep v8 memory usage as low as possible. // memory usage as low as possible.
// Calling immediately after a runMessageLoop ensure self._session.browser.env.memoryPressureNotification(.moderate);
self._session.browser.env.lowMemoryNotification();
self._script_manager.shutdown = true; self._script_manager.shutdown = true;
self._session.browser.http_client.abort(); self._session.browser.http_client.abort();

View File

@@ -24,6 +24,7 @@ const log = @import("../../log.zig");
const bridge = @import("bridge.zig"); const bridge = @import("bridge.zig");
const Context = @import("Context.zig"); const Context = @import("Context.zig");
const Isolate = @import("Isolate.zig");
const Platform = @import("Platform.zig"); const Platform = @import("Platform.zig");
const Snapshot = @import("Snapshot.zig"); const Snapshot = @import("Snapshot.zig");
const Inspector = @import("Inspector.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 // a Context, it's managed by the garbage collector. We use the
// `lowMemoryNotification` call on the isolate to encourage v8 to free // `lowMemoryNotification` call on the isolate to encourage v8 to free
// any contexts which have been freed. // any contexts which have been freed.
// This GC is very aggressive. Use memoryPressureNotification for less
// aggressive GC passes.
pub fn lowMemoryNotification(self: *Env) void { pub fn lowMemoryNotification(self: *Env) void {
var handle_scope: js.HandleScope = undefined; var handle_scope: js.HandleScope = undefined;
handle_scope.init(self.isolate); handle_scope.init(self.isolate);
@@ -200,6 +203,21 @@ pub fn lowMemoryNotification(self: *Env) void {
self.isolate.lowMemoryNotification(); 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 { pub fn dumpMemoryStats(self: *Env) void {
const stats = self.isolate.getHeapStatistics(); const stats = self.isolate.getHeapStatistics();
std.debug.print( std.debug.print(

View File

@@ -57,6 +57,16 @@ pub fn lowMemoryNotification(self: Isolate) void {
v8.v8__Isolate__LowMemoryNotification(self.handle); 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 { pub fn notifyContextDisposed(self: Isolate) void {
_ = v8.v8__Isolate__ContextDisposedNotification(self.handle); _ = v8.v8__Isolate__ContextDisposedNotification(self.handle);
} }