ESP32 heap and stack monitoring in the field

Most ESP32 devices that fail after three weeks fail for one of two reasons: the heap slowly ran out, or a task's stack was nearly full on the desk and overflowed in the field. Both are visible long before the crash, if you look at four numbers.

The four numbers

size_t free_now     = esp_get_free_heap_size();
size_t free_minimum = esp_get_minimum_free_heap_size();
size_t largest      = heap_caps_get_largest_free_block(MALLOC_CAP_DEFAULT);
UBaseType_t stack   = uxTaskGetStackHighWaterMark(NULL);   /* of this task, in bytes */
NumberWhat it tells you
Free heapHow much is free right now. On its own it says little: it moves with every request.
Minimum free heapThe lowest the heap has been since start. This is your real margin: the worst moment so far.
Largest free blockThe biggest single allocation that would succeed. When this is much smaller than the free heap, the heap is fragmented, and a large malloc can fail with plenty of memory free.
Stack high-water markThe least free stack a task has ever had. Near zero means the next deeper call overflows it.

Reading them over time

One reading is nearly useless. The shape over days is what finds the bug.

Every task, not just yours

With CONFIG_FREERTOS_USE_TRACE_FACILITY, uxTaskGetSystemState() returns the high-water mark of every task, including the ones you did not write: the WiFi task, the TCP/IP task, the event loop, the HTTP server. Those overflow too, usually because a callback of yours runs on their stack.

Getting the numbers off the device

Printing them to the log every minute works on the desk. For devices in the field they have to travel, and they should be drawn as a line over time, because the shape is the information.

Pinscope reports all of these with no code: free heap, minimum and largest block, the least free stack of any task and of each task, WiFi signal, chip temperature and restarts by reason, once a minute, kept as history. Your own numbers are one call:

pinscope_metric("queue_depth", depth);

The component itself takes a fixed 9.4 KB of RAM, so it does not move the numbers it reports.

Before shipping

Try it

Three devices are free with every feature, and no card is needed. Create an account, or read the five-minute guide first.

More