Runtime memory tracing
Running out of memory is a common problem with resource constrained systems such as the MCUs on which Arm Mbed OS runs. When faced with an out of memory error, you often need to understand how your software uses dynamic memory. The runtime memory tracer in Mbed OS is the tool that shows the runtime memory allocation patterns of your software: which parts of the code allocate and free memory and how much memory they need.
Using the memory tracer
The memory tracer is not enabled by default. To enable it, you need to enable the memory-tracing-enabled
setting in the Mbed OS platform configuration options. We recommend doing this by adding it to your mbed_app.json
:
{
"target_overrides": {
"*": {
"platform.memory-tracing-enabled": true
}
}
}
Tip: See the documentation of the Arm Mbed configuration system for more details about mbed_app.json
.
After it is enabled, the memory tracer intercepts the calls to the standard allocation functions (malloc
, realloc
, calloc
and free
). It invokes a user supplied callback each time one of these functions is called. To let the tracer know which callback it needs to invoke, call mbed_mem_trace_set_callback(callback_function_name)
as early as possible (preferably at the beginning of your main
function). You can find the full documentation of the callback function in the memory tracer header file. The tracer supplies a default callback function (mbed_mem_trace_default_callback
) that outputs trace data on the Mbed console (using printf
). For each memory operation, the callback outputs a line that begins with #<op>:<0xresult>;<0xcaller>-
:
- op identifies the memory operation (
m
formalloc
,r
forrealloc
,c
forcalloc
andf
forfree
). - result (base 16) is the result returned by the memory operation. This is always 0 for
free
becausefree
doesn't return anything. - caller (base 16) is the address in the code where the memory operation was called.
The rest of the output depends on the operation being traced:
- For
malloc
:size
, wheresize
is the original argument tomalloc
. - For
realloc
:0xptr;size
, whereptr
(base 16) andsize
are the original arguments torealloc
. - For
calloc
:nmemb;size
, wherenmemb
andsize
are the original arguments tocalloc
. - For
free
:0xptr
, whereptr
(base 16) is the original argument tofree
.
Examples:
#m:0x20003240;0x600d-50
encodes amalloc
that returned 0x20003240. It was called by the instruction at 0x600D with thesize
argument equal to 50.#f:0x0;0x602f-0x20003240
encodes afree
that was called by the instruction at 0x602f with theptr
argument equal to 0x20003240.
Find the source of the default callback here. Besides being useful in itself, it can also serve as a template for user defined callback functions.
Tip: Find the full documentation of the callback function in the memory tracer header file.
Example
A simple code example that uses the memory tracer on a K64F board:
/*
* Copyright (c) 2020 Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdlib.h>
#include "mbed.h"
#include "mbed_mem_trace.h"
int main()
{
mbed_mem_trace_set_callback(mbed_mem_trace_default_callback);
while (true) {
void *p = malloc(50);
printf("50B allocated at %p\n", p);
ThisThread::sleep_for(500);
free(p);
printf("50B freed at %p\n\n", p);
}
}
It outputs the following trace:
#m:0x20003080;0x182f-50
#f:0x0;0x183f-0x20003080
#m:0x20003080;0x182f-50
#f:0x0;0x183f-0x20003080
#m:0x20003080;0x182f-50
#f:0x0;0x183f-0x20003080
...
Limitations
- The tracer doesn't handle nested calls of the memory functions. For example, if you call
realloc
and the implementation ofrealloc
callsmalloc
internally, the call tomalloc
is not traced. - The caller argument of the callback function isn't always reliable. It doesn't work at all on some toolchains, and it might output erroneous data on others.