mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-29 15:13:28 +00:00
Introduce a "transfer_arena"
Some data has to exist specifically for the navigation of one page to another. For example, if a hyperlink is clicked, the URL begins its life with the original page, but is transferred to the new page. The page_arena cannot be used for such data. It's possible to use the session_arena, but it's lifetime is much longer and, given enough navigation, could accumulate a lot of memory. The new transfer_arena exists within the session, but only exists until the next navigation. While currently only used for the navigation URL, the main goal here is to have a place to put the request body on form submission, which has a lifetime similar to a click url. While I'm at it, I promoted the existing session arena and the new transfer arena to the browser, allowing better memory re-use between sessions.
This commit is contained in:
@@ -38,6 +38,8 @@ pub const Browser = struct {
|
|||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
http_client: *http.Client,
|
http_client: *http.Client,
|
||||||
page_arena: ArenaAllocator,
|
page_arena: ArenaAllocator,
|
||||||
|
session_arena: ArenaAllocator,
|
||||||
|
transfer_arena: ArenaAllocator,
|
||||||
notification: *Notification,
|
notification: *Notification,
|
||||||
|
|
||||||
pub fn init(app: *App) !Browser {
|
pub fn init(app: *App) !Browser {
|
||||||
@@ -57,6 +59,8 @@ pub const Browser = struct {
|
|||||||
.notification = notification,
|
.notification = notification,
|
||||||
.http_client = &app.http_client,
|
.http_client = &app.http_client,
|
||||||
.page_arena = ArenaAllocator.init(allocator),
|
.page_arena = ArenaAllocator.init(allocator),
|
||||||
|
.session_arena = ArenaAllocator.init(allocator),
|
||||||
|
.transfer_arena = ArenaAllocator.init(allocator),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,6 +68,8 @@ pub const Browser = struct {
|
|||||||
self.closeSession();
|
self.closeSession();
|
||||||
self.env.deinit();
|
self.env.deinit();
|
||||||
self.page_arena.deinit();
|
self.page_arena.deinit();
|
||||||
|
self.session_arena.deinit();
|
||||||
|
self.transfer_arena.deinit();
|
||||||
self.notification.deinit();
|
self.notification.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,6 +85,7 @@ pub const Browser = struct {
|
|||||||
if (self.session) |*session| {
|
if (self.session) |*session| {
|
||||||
session.deinit();
|
session.deinit();
|
||||||
self.session = null;
|
self.session = null;
|
||||||
|
_ = self.session_arena.reset(.{ .retain_with_limit = 1 * 1024 * 1024 });
|
||||||
if (self.app.config.gc_hints) {
|
if (self.app.config.gc_hints) {
|
||||||
self.env.lowMemoryNotification();
|
self.env.lowMemoryNotification();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
const ArenaAllocator = std.heap.ArenaAllocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
const Env = @import("env.zig").Env;
|
const Env = @import("env.zig").Env;
|
||||||
const Page = @import("page.zig").Page;
|
const Page = @import("page.zig").Page;
|
||||||
@@ -37,7 +37,17 @@ pub const Session = struct {
|
|||||||
browser: *Browser,
|
browser: *Browser,
|
||||||
|
|
||||||
// Used to create our Inspector and in the BrowserContext.
|
// Used to create our Inspector and in the BrowserContext.
|
||||||
arena: ArenaAllocator,
|
arena: Allocator,
|
||||||
|
|
||||||
|
// The page's arena is unsuitable for data that has to existing while
|
||||||
|
// navigating from one page to another. For example, if we're clicking
|
||||||
|
// on an HREF, the URL exists in the original page (where the click
|
||||||
|
// originated) but also has to exist in the new page.
|
||||||
|
// While we could use the Session's arena, this could accumulate a lot of
|
||||||
|
// memory if we do many navigation events. The `transfer_arena` is meant to
|
||||||
|
// bridge the gap: existing long enough to store any data needed to end one
|
||||||
|
// page and start another.
|
||||||
|
transfer_arena: Allocator,
|
||||||
|
|
||||||
executor: Env.Executor,
|
executor: Env.Executor,
|
||||||
storage_shed: storage.Shed,
|
storage_shed: storage.Shed,
|
||||||
@@ -53,9 +63,10 @@ pub const Session = struct {
|
|||||||
self.* = .{
|
self.* = .{
|
||||||
.browser = browser,
|
.browser = browser,
|
||||||
.executor = executor,
|
.executor = executor,
|
||||||
.arena = ArenaAllocator.init(allocator),
|
.arena = browser.session_arena.allocator(),
|
||||||
.storage_shed = storage.Shed.init(allocator),
|
.storage_shed = storage.Shed.init(allocator),
|
||||||
.cookie_jar = storage.CookieJar.init(allocator),
|
.cookie_jar = storage.CookieJar.init(allocator),
|
||||||
|
.transfer_arena = browser.transfer_arena.allocator(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,7 +74,6 @@ pub const Session = struct {
|
|||||||
if (self.page != null) {
|
if (self.page != null) {
|
||||||
self.removePage();
|
self.removePage();
|
||||||
}
|
}
|
||||||
self.arena.deinit();
|
|
||||||
self.cookie_jar.deinit();
|
self.cookie_jar.deinit();
|
||||||
self.storage_shed.deinit();
|
self.storage_shed.deinit();
|
||||||
self.executor.deinit();
|
self.executor.deinit();
|
||||||
@@ -116,12 +126,12 @@ pub const Session = struct {
|
|||||||
// it isn't null!
|
// it isn't null!
|
||||||
std.debug.assert(self.page != null);
|
std.debug.assert(self.page != null);
|
||||||
|
|
||||||
// can't use the page arena, because we're about to reset it
|
_ = self.browser.transfer_arena.reset(.{ .retain_with_limit = 1 * 1024 * 1024 });
|
||||||
// and don't want to use the session's arena, because that'll start to
|
|
||||||
// look like a leak if we navigate from page to page a lot.
|
// it's safe to use the transfer arena here, because the page will
|
||||||
var buf: [2048]u8 = undefined;
|
// eventually clone the URL using its own page_arena (after it gets
|
||||||
var fba = std.heap.FixedBufferAllocator.init(&buf);
|
// the final URL, possibly following redirects)
|
||||||
const url = try self.page.?.url.resolve(fba.allocator(), url_string);
|
const url = try self.page.?.url.resolve(self.transfer_arena, url_string);
|
||||||
|
|
||||||
self.removePage();
|
self.removePage();
|
||||||
var page = try self.createPage();
|
var page = try self.createPage();
|
||||||
|
|||||||
@@ -314,7 +314,7 @@ pub fn BrowserContext(comptime CDP_T: type) type {
|
|||||||
const allocator = cdp.allocator;
|
const allocator = cdp.allocator;
|
||||||
|
|
||||||
const session = try cdp.browser.newSession();
|
const session = try cdp.browser.newSession();
|
||||||
const arena = session.arena.allocator();
|
const arena = session.arena;
|
||||||
|
|
||||||
const inspector = try cdp.browser.env.newInspector(arena, self);
|
const inspector = try cdp.browser.env.newInspector(arena, self);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user