atproto relay implementation in zig zlay.waow.tech
9
fork

Configure Feed

Select the types of activity you want to include in your feed.

revert exp-001: SmpAllocator grew RSS faster than c_allocator

SmpAllocator RSS grew at ~670 MiB/hour vs c_allocator's ~290 MiB/hour.
disproves glibc fragmentation hypothesis — the leak is genuine.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

zzstoatzz 84067b7e 0fe7efd5

+12 -8
+5 -1
EXPERIMENTS.md
··· 49 49 log.info("gc: malloc_trim complete", .{}); 50 50 ``` 51 51 52 - **status**: active 52 + **result**: FAILED — RSS grew at ~670 MiB/hour (worse than c_allocator's ~290 MiB/hour). 53 + this disproves glibc fragmentation as the root cause. the leak is genuine — memory is 54 + allocated and never freed. reverted to c_allocator. 55 + 56 + **status**: reverted (2026-03-07)
+7 -7
src/main.zig
··· 119 119 } 120 120 121 121 pub fn main() !void { 122 - // use zig's SmpAllocator — thread-local freelists backed by mmap/munmap. 123 - // c_allocator (glibc malloc) caused linear RSS growth under cross-thread 124 - // alloc/free patterns: subscriber threads alloc, worker threads free, 125 - // glibc's per-thread arenas fragment and never return pages to the OS. 126 - // see EXPERIMENTS.md exp-001. 127 - const allocator = std.heap.smp_allocator; 122 + // use libc allocator (glibc malloc). SmpAllocator was tested (exp-001) 123 + // and grew RSS even faster — the leak is genuine, not glibc fragmentation. 124 + const allocator = std.heap.c_allocator; 128 125 129 126 // parse config from env 130 127 const port = parseEnvInt(u16, "RELAY_PORT", 3000); ··· 264 261 log.info("relay stopped cleanly", .{}); 265 262 } 266 263 264 + const malloc_h = @cImport(@cInclude("malloc.h")); 265 + 267 266 fn gcLoop(dp: *event_log_mod.DiskPersist) void { 268 267 const gc_interval: u64 = 10 * 60; // 10 minutes in seconds 269 268 while (!shutdown_flag.load(.acquire)) { ··· 280 279 log.warn("event log GC failed: {s}", .{@errorName(err)}); 281 280 }; 282 281 283 - log.info("gc: complete", .{}); 282 + _ = malloc_h.malloc_trim(0); 283 + log.info("gc: malloc_trim complete", .{}); 284 284 } 285 285 } 286 286