Layered ArenaAllocator

Following code has been reported a memory leak by GeneralPurposeAllocator.

const std = @import("std");

const Foo = struct {
    arena: *std.heap.ArenaAllocator,
    x1: []const u8,
    x2: []const u8,

    pub fn init(allocator: std.mem.Allocator) !Foo {
        var arena = try allocator.create(std.heap.ArenaAllocator);
        arena.* = std.heap.ArenaAllocator.init(allocator);

        const a = arena.allocator();

        return .{
            .arena = arena,
            .x1 = try a.dupe(u8, "X1"),
            .x2 = try a.dupe(u8, "X2"),
    pub fn deinit(self: *Foo) void {
        const a = self.arena.child_allocator;

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    var arena = std.heap.ArenaAllocator.init(gpa.allocator());
    defer {
        std.debug.print("Leak?: {}\n", .{gpa.detectLeaks()}); // <----- Report memory leaks

    var foo = try Foo.init(arena.allocator());
    defer foo.deinit();

Foo instance release themselves arena to return memory to parent arena.
But a memory leak is reported by gpa.

Sometime, realloc has occured, memory leaks is reported from gpa.
It seems that the ArenaAllocator is pooling the returned memory.

Is this layered ArenaAllocator the anti-pattern?

$ zig version

You perform the leak check before you call arena.deinit(), so naturally it thinks that you leaked memory.

Also I would recommend to call gpa.deinit() in the future, this will also free the OS resource and still give you a detailed stacktrace of where the leaked memory got allocated.


Two memory leaks found.

One is I created…oh
Other one is due to patch to package. (the original code is not leaks but occur seffault)

And nested ArenaAllocator has no problem.