Zprof is a cross-allocator wrapper for profiling memory data.
Developed for use in Debug or official modes, it guarantees nearly the same performance as the wrapped allocator. Zprof's development is based on a primary priority: ease of use, improved efficiency, readability, clean, minimal, and well-documented code.
- The Zprof cross-allocator profiler
- ๐ Table of Contents
- ๐ฅ Installation
- ๐ Quick Start
- ๐ Usage
- ๐ Examples
Add Zprof
to your project's build.zig.zon
:
.{
.name = "my-project",
.version = "1.2.0",
.dependencies = .{
.zprof = .{
.url = "https://github.com/ANDRVV/zprof/archive/v1.2.0.zip",
.hash = "...",
},
},
}
Then in your build.zig
, add:
// Add Zprof as a dependency
const zprof_dep = b.dependency("zprof", .{
.target = target,
.optimize = optimize,
});
// Add the module to your executable
exe.root_module.addImport("zprof", zprof_dep.module("zprof"));
Else can you you put zprof.zig
in yours project path and import it.
Here's how to use Zprof
in three easy steps:
const std = @import("std");
const Zprof = @import("zprof").Zprof;
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
var gpa_allocator = gpa.allocator();
// 1. Create a profiler by wrapping your allocator
var zprof = try Zprof(false).init(&gpa_allocator, true);
// false disable thread-safe mode and true enables logging
defer zprof.deinit(); // deallocates Zprof instance
// 2. Use the profiler's allocator instead of your original one
const allocator = zprof.allocator;
// 3. Use the allocator as normal
const data = try allocator.alloc(u8, 1024);
defer allocator.free(data);
// Check for leaks
std.debug.print("Has leaks: {}\n", .{zprof.profiler.hasLeaks()});
}
To start profiling memory usage, simply wrap your allocator with Zprof
:
var zprof = try Zprof(false).init(&allocator, false); // on init, false disables automatic logging
const tracked_allocator = zprof.allocator;
To use Zprof
with mutex, you must enable thread-safe mode:
var zprof = try Zprof(true).init(&allocator, false); // true enables thread-safe mode
const tracked_allocator = zprof.allocator;
If logging is enabled, logs allocated/deallocated bytes when allocator allocates or deallocates.
var zprof = try Zprof(false).init(&allocator, true); // true enables automatic logging
const tracked_allocator = zprof.allocator;
const data = try allocator.alloc(u8, 1024); // prints: Zprof::ALLOC allocated=1024
allocator.free(data); // prints: Zprof::FREE deallocated=1024
Zprof
makes it easy to detect memory leaks in your application:
// At the end of your program or test
const has_leaks = zprof.profiler.hasLeaks();
if (has_leaks) {
// Handle leaks (e.g., report, abort in tests)
std.debug.print("Memory leak detected!\n", .{});
return error.MemoryLeak;
}
The Profiler
struct contains several fields and methods:
Field | Type | Description |
---|---|---|
allocated |
u64 |
Total bytes allocated since initialization |
alloc_count |
u64 |
Number of allocation operations |
free_count |
u64 |
Number of deallocation operations |
live_peak |
u64 |
Maximum memory usage at any point |
live_bytes |
u64 |
Current memory usage |
Method | Description |
---|---|
hasLeaks() |
Returns true if there are memory leaks |
reset() |
Resets all profiling statistics |
test "no memory leaks" {
var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
defer arena.deinit();
var arena_allocator = arena.allocator();
var zprof = try Zprof(false).init(&arena_allocator, false);
defer zprof.deinit();
const allocator = zprof.allocator;
// Perform allocations
const data = try allocator.alloc(u8, 1024);
defer allocator.free(data);
// Verify no leaks
try std.testing.expect(!zprof.profiler.hasLeaks());
}
Made with โค๏ธ for the Zig community
Copyright (c) 2025 Andrea Vaccaro