# heaptrack: tracing heap allocations on Linux without a debugger session

> heaptrack records every malloc and free in a running process, annotates them with stack traces, and hands you a compressed trace to analyze later. It is built for Linux, and the GUI half of it needs Qt 5 and KDE Frameworks 5.

**KDE/heaptrack** — A heap memory profiler for Linux

- Repository: https://github.com/KDE/heaptrack
- Website: https://invent.kde.org/sdk/heaptrack
- Stars: 4,172 · Forks: 244
- Language: C++
- License: not declared
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/kde-heaptrack

## What heaptrack records that a leak checker does not

heaptrack is a sampling-free allocation tracer. According to the README, it "traces all memory allocations and annotates these events with stack traces." That phrasing matters: the tool is not asking whether an address is valid, it is building a timeline of allocation events with the call stack that produced each one. From that timeline the README lists four things you can extract: hotspots that inflate the memory footprint, leaks (locations that allocate memory which is never deallocated), allocation hotspots that fire many times, and temporary allocations that are allocated and freed back to back.

The audience is narrow on purpose. If your program is a short-lived command line tool that exits in 200 milliseconds, the trace is mostly noise. If it is a server that runs for days and slowly grows, the trace is exactly the artifact you want, because the leak is defined at exit time by allocations that were never matched by a free. The README's own example output makes the distinction concrete, printing separate counters for allocations, leaked allocations and temporary allocations. Those three numbers alone tell you whether you are chasing a leak or chasing churn.

## How tracing, injection and interpretation fit together

There are two ways to get data out of a process. The first is to launch it under heaptrack, which is the recommended path in the README because tracing starts from the beginning and you miss nothing during startup. The second is to attach to a process that is already running with heaptrack --pid, which the README says injects heaptrack into the application via GDB. That injection step is why gdb is listed as a runtime requirement for attaching, and it is also why attaching is the weaker option: everything allocated before the injection is invisible.

On disk, the collector writes a compressed trace, by default to /tmp/heaptrack.APP.PID.gz. The README is explicit that these files are "impossible to analyze for a human," which is the whole reason the analyze step exists. heaptrack_print is described as the simplistic text analyzer, and heaptrack_gui is the graphical one built on Qt 5 and KDE Frameworks 5. The GUI is optional at build time: the README states that when any of its dependencies is missing, heaptrack_gui will not be built, while the collector still is.

The third path is the one embedded developers actually need. If you have no debug symbols on the target, you record with heaptrack --raw, move the raw trace to a development machine, and run heaptrack --interpret with a --sysroot pointing at the matching SDK or sysroot. Only after interpretation do you run --analyze. The README also mentions --debug-paths for debug information outside the sysroot and --extra-paths for side-loaded binaries built in their own build folders. That split between recording and interpretation is the most interesting design decision in the project, and it is what separates it from tools that assume the debug info is on the same machine.

## Installing heaptrack on Ubuntu and other Linux distributions

The README does not give a package installation command. It points at development packages on major distributions for the dependency list, and it directs anyone who needs help building, deploying or using heaptrack to KDAB for commercial support. So the honest answer to "how do I install heaptrack" is: check your distribution's package for heaptrack, or build it from source. If you build it, the README gives this sequence.

```bash
cd heaptrack
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
make -j$(nproc)
```

The README warns you to pay attention to the CMake output because it reports missing dependencies. Do that literally: if Qt 5 or the KDE Frameworks 5 modules are absent, you will get the collector and heaptrack_print but no GUI, and the build will not fail to tell you. The collector itself needs cmake 2.8.9 or higher, a C++11 compiler, zlib, elfutils, libdl, pthread, libc, boost 1.41 or higher (iostreams and program_options) and libunwind. zstd is optional but the README lists it as giving faster compression and decompression.

The first real use is a single command. Run your program under the profiler and read the summary it prints.

```bash
heaptrack <your application and its parameters>
```

You should see a line naming the output file, typically /tmp/heaptrack.APP.PID.gz, then a stats block with allocations, leaked allocations and temporary allocations, then a message telling you the exact --analyze command to run next. Copy that command rather than reconstructing the path by hand; the PID is embedded in the filename.

If the program is already running and you cannot restart it, attach instead. The README shows this form.

```bash
heaptrack --pid $(pidof <your application>)
```

Expect a pause while GDB injects the profiler, and expect the trace to be empty for everything the process did before that moment.

## Profiling an embedded target with a sysroot on the build machine

The embedded workflow is where heaptrack's architecture earns its keep, and it is also where it is easiest to get wrong. On the device you record a raw trace, which needs no debug symbols and no GUI.

```bash
heaptrack --raw <your application and its parameters>
```

Then you copy the raw file to a development machine that has the matching sysroot and interpret it there.

```bash
heaptrack --interpret "/path/heaptrack.test_c.8911.raw.zst" --sysroot "/path/to/sysroot"
```

The README notes that if you have custom code side-loaded and want debug information from the respective build folders, you add --extra-paths. For debug information that lives outside the sysroot entirely, --debug-paths is the flag, and the README links to the GDB documentation on separate debug files for the layout it expects. The failure mode here is a sysroot that does not match the binaries on the device: symbols resolve to the wrong addresses or not at all, and you get a trace full of unresolved frames that looks like a profiler bug but is a deployment mistake.

## Where heaptrack is the wrong tool

heaptrack is a heap profiler, not a memory error detector. It will not tell you about a buffer overflow, a use-after-free, or an uninitialized read. If the bug you are hunting corrupts data rather than leaks memory, this is the wrong instrument and the trace will be clean.

Second, the platform boundary is real. The README describes heaptrack as a heap memory profiler for Linux, and its collector depends on libunwind and elfutils. The macOS section of the README is not about the collector at all: it builds heaptrack_gui and heaptrack_print from source via homebrew and the KDE homebrew tap, so you can analyze traces on a Mac, but the README does not present macOS as a supported tracing target. If you are looking for heaptrack on Windows, nothing in the documentation supports it.

Third, the attach path has a blind spot that people hit in production. Injecting into a running process via GDB means the allocations from process startup, config loading and connection pool warmup are simply absent from the trace. For a leak that starts at the first request, that is fine. For a leak in initialization code, you need to launch under the profiler instead.

Finally, there is a build-cost limitation that is easy to underestimate. The GUI needs Qt 5.2 or higher plus KDE Frameworks 5 modules (CoreAddons, I18n, ItemModels, ThreadWeaver, ConfigWidgets, KIO, IconThemes) and extra-cmake-modules, with KDiagram's KChart optional for charts. On a minimal CI image or an older distribution, you will end up with the collector only. The README treats that as an acceptable outcome, and for scripted analysis with heaptrack_print it is.

## heaptrack versus valgrind for allocation work

The comparison people reach for is valgrind, and the difference is not speed alone, it is what each tool is designed to answer. Valgrind's memcheck runs your program on a synthetic CPU and checks every memory access for errors, which is why it catches invalid reads and writes. heaptrack does not emulate the CPU. It traces allocation calls and records the stacks behind them, so it answers "who allocated this and did they free it" rather than "was this access legal."

That distinction changes the workflow. A valgrind run is typically a bounded, slower execution you schedule deliberately. A heaptrack trace can be taken from a process you launch normally, or injected into one that is already serving traffic, which matters when the memory growth only reproduces under real load. The other practical difference is the embedded path: heaptrack's raw recording plus later --interpret against a sysroot is a documented workflow, and it exists precisely because the target cannot carry debug symbols or a GUI. That is a different shape of tool from a debugger-class checker that wants everything on one machine.

If you want to see the difference on your own code, run the same binary under both and compare what each reports. heaptrack will give you a leaked-allocation count and the call sites behind it. It will not give you a line number for an out-of-bounds write.

## Release cadence, licensing and what to check before adopting

The release history is thin. v1.3.0 landed on 2021-12-21 with time based filtering, suppressions, better performance and improved FreeBSD support, and v1.2.0 before it on 2020-09-02 was described as improved stability. The repository's last push was on 2026-09-23, so development activity on master is recent even though the tagged releases are years apart. The practical consequence is that if you want time based filtering or suppressions, you should check whether your distribution's package is at v1.3.0 or whether you need to build from master.

The repository carries a LICENSES/ directory and a .reuse/ directory, which is the REUSE tooling KDE projects use to declare per-file licensing, but the licence identifier is not stated in the README. Do not assume a licence from the project's host or its KDE affiliation; read the files under LICENSES/ yourself before you vendor anything. Nothing here is legal advice, and the licence question is the one thing you cannot resolve by reading the README.

Upgrade cost is mostly a build-environment question. The dependency list is long and split in two, and the GUI half drags in Qt 5 and KDE Frameworks 5, which is a heavy addition to a CI image that only needs to analyze traces. Building the collector alone and running heaptrack_print on the resulting file is the cheaper path, and the README explicitly supports it by describing the two parts as buildable independently.

## Conclusion

heaptrack fits teams shipping long-running C, C++ or Rust services on Linux who need to know which call sites hold memory at exit, and embedded developers who can record a raw trace on the device and interpret it later against a sysroot. It is the wrong tool if you need per-instruction memory error detection, if you cannot install libunwind and elfutils on the build host, or if you expect the GUI on a machine without Qt 5 and KDE Frameworks 5. Before adopting it, verify three things on your own distribution: that your packaged build includes the collector, that gdb is present if you plan to use --pid, and that zstd is available if you want the faster compression path. The README documents the raw trace plus --interpret workflow as the supported answer for systems without debug symbols, so check that path against your sysroot before you promise anyone a flame graph.

## FAQ

### How do I use heaptrack to profile a program?

Launch the application under the profiler with heaptrack followed by the program and its parameters, or attach to a running process with heaptrack --pid. The trace is written to /tmp/heaptrack.APP.PID.gz and the README prints the exact --analyze command to run next.

### What is heaptrack?

It is a heap memory profiler for Linux that traces all memory allocations and annotates them with stack traces. The README lists four uses: finding memory footprint hotspots, memory leaks, allocation hotspots and temporary allocations.

### What is heaptrack analyze for?

heaptrack writes data files the README calls impossible for a human to analyze, so the analyze step interprets the trace. heaptrack_print is the text analyzer and heaptrack_gui is the graphical one.

## Sources

- [Issues](https://github.com/KDE/heaptrack/issues)
- [KDE/heaptrack on GitHub](https://github.com/KDE/heaptrack)
- [Project website](https://invent.kde.org/sdk/heaptrack)
- [README](https://github.com/KDE/heaptrack/blob/master/README.md)
- [Releases](https://github.com/KDE/heaptrack/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/kde-heaptrack
