Memory Hound, also known as mhound, is a tool for recording the memory usage of arbitrary processes and analysing the collected data, so that programmers can optimise their programs and detect memory-related bugs such as memory leaks. It consists of two components:
- The tracer which is responsible for collecting memory usage data.
- The analyser which is responsible for allowing the user to analyse the collected data.
Install Clang and CMake for the tracer and Node.js and NPM for the analyser:
sudo apt update
sudo apt install clang cmake nodejs npmConfirm that all four tools are installed:
clang -v
cmake --version
node -v
npm -vMemory Hound has been tested with the following versions:
Ubuntu clang version 14.0.0-1ubuntu1.1
cmake version 3.22.1
node v22.14.0
npm 10.9.2There is a script offered that should automatically build the tracer and analyser, however if this does not work there are manual build instructions.
At the root of the project, run the following command to build the tracer and analyser:
sudo ./Build.shConfirm that the newly created Build directory has the following files and directories:
mhound(tracer launcher)libmhound-tracer.so(tracer attachment)UnitTestRunner(unit test runner for the tracer)IntegrationTestRunner(integration test runner for the tracer)IntegrationTestPrograms(some programs used as part of the integration test)analyser(directory containing the analyser)
If you are building manually because the automatic script failed, you may want to reset the project.
At the root of the project, create a Build directory to store build artefacts.
Navigate to the Tracer directory and run the following commands:
cmake -B build
cmake --build buildGo inside of the build directory and copy mhound, libmhound-tracer.so, UnitTestRunner, IntegrationTestPrograms, and IntegrationTestRunner to the Build directory created before.
Navigate to the Analyser directory and run the following commands:
npm install
sudo npm run makeGo inside of the out/make/zip directory and keep going down until you find a .zip.
Create an analyser directory in the Build directory.
Extract the contents of the .zip. You will get a directory structure like mhound-linux-x64-1.0.0 with another mhound-linux-x64-1.0.0 inside and then inside of that there will be all of the files for the analyser. Copy only these inner files and directories to the analyser directory. You should end up with an executable at path Build/analyser/mhound.
To run the unit tests for the tracer, run the following executable:
./Build/UnitTestRunnerTo run the integration test for the tracer, run the following executable:
./Build/IntegrationTestRunnerFor both of these, you can use the --help flag to get more options. For instance, -s will show successful test cases.
Create an example program such as:
#include <malloc.h>
int main() {
void* ptr1 = malloc(4);
void* ptr2 = malloc(6);
free(ptr1);
void* ptr3 = malloc(10);
free(ptr2);
free(ptr3);
}and save it as main.cpp.
Build the program using Clang:
clang++ -g -O0 -no-pie -gdwarf-4 main.cpp -o appThese flags are all important:
-gtells Clang to build the executable with debug symbols and-gdwarf-4tells Clang to include DWARF 4 debugging information. This debugging information is used by Memory Hound to generate readable backtraces for calls to memory management functions.-O0tells Clang not to make optimisations. This stops Clang from optimising away functions which makes the backtraces less readable.-no-pietells Clang not to build a position-independent executable. PIE is a mechanism that randomises the base address of an executable each time it is executed, which is great for security but bad for Memory Hound trying to figure out addresses in the backtrace.
Memory Hound will work without these flags but there will not be readable/useful backtraces.
ASLR (Address Space Layout Randomisation) is a security technique that randomises the memory addresses where executables and libraries are loaded. Compiling the target program as -no-pie does ensure the executable's code remains at a predictable location, but other aspects of the virtual memory such as the heap will still be randomised. Disabling ASLR can make some of e.g. the pointers returned by malloc() more predictable. This is not strictly necessary though.
Disable ASLR with:
sudo sysctl -w kernel.randomize_va_space=0ASLR is reenabled after a system reboot.
Navigate to executable ./Build/mhound (this is the tracer) and run it on the target executable:
./mhound ./appWARNING: Memory Hound cannot figure out executables from the PATH environment variable, so the full path to a program must be specified, e.g. ./mhound /usr/bin/ls instead of ./mhound ls.
The tracer should generate a trace/ directory and inside there should be a trace.json file. Confirm this exists before proceeding.
Start the analyser which is also in ./Build:
./analyser/mhoundThis will open a GUI window. Click on "Load a new trace" and open the trace.json file.
You can look at the tabs on the left side to see different information. For instance, the cumulative memory usage over time is shown below:
This maps to what we would expect from the example program.

