glibc hands each new thread its own 64 MiB arena (up to 8x cores). With one thread per connection that arena is the dominant per-connection memory term, and freed chunks stay reserved in it rather than returning to the OS: resident memory tracks the *peak* number of concurrent connections and never comes back down, which reads as a leak although nothing is leaked and no thread is stuck. Measured with reliability/conn-scale.py in obscura-benchmark. 100 connections each running JS reserve 90.0 GiB of address space uncapped versus 83.5 GiB capped; per idle connection, 65 MiB of reserved address space drops to 2.0 MiB. `main` at that same 100-connection JS workload reserves 83.6 GiB, so with the cap this server is level with it -- most of the total is V8's process-wide sandbox, which `main` pays too the moment it runs any JS. The resident-set effect is the one that bites in production. Measured in the container image against Google Maps, four concurrent connections per round: 350 / 619 / 826 MiB over three rounds uncapped and still climbing linearly, versus 166 / 235 / 269 MiB capped, on a decelerating curve. Two arenas cost no measurable throughput here -- 8 concurrent connections x 12 navigations, 1.53s uncapped against 1.50s capped over three runs. V8 allocates the JS heap through its own allocator and the Rust side is dominated by network I/O rather than malloc traffic. Applied only from `serve`, which owns the process, and skipped when the caller has already set MALLOC_ARENA_MAX. Refs #430.
29 lines
703 B
TOML
29 lines
703 B
TOML
[package]
|
|
name = "obscura-cdp"
|
|
version.workspace = true
|
|
edition.workspace = true
|
|
|
|
[dependencies]
|
|
obscura-dom = { workspace = true }
|
|
obscura-browser = { workspace = true }
|
|
obscura-js = { workspace = true }
|
|
tokio = { workspace = true }
|
|
tokio-tungstenite = { workspace = true }
|
|
serde = { workspace = true }
|
|
serde_json = { workspace = true }
|
|
url = { workspace = true }
|
|
uuid = { workspace = true }
|
|
tracing = { workspace = true }
|
|
thiserror = { workspace = true }
|
|
anyhow = { workspace = true }
|
|
futures-util = "0.3"
|
|
base64 = "0.22"
|
|
obscura-net = { workspace = true }
|
|
|
|
[target.'cfg(target_env = "gnu")'.dependencies]
|
|
libc = "0.2"
|
|
|
|
[dev-dependencies]
|
|
tokio-tungstenite = { workspace = true }
|
|
futures-util = "0.3"
|