Code: Select all
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "esp_heap_trace.h"
#include "esp_heap_caps.h"
#define NUM_RECORDS 10
static heap_trace_record_t traceRecord[NUM_RECORDS];
void app_main(void)
{
SemaphoreHandle_t mutex1;
SemaphoreHandle_t mutex2;
size_t heapUsed;
size_t heapUsedAtStart;
heap_trace_init_standalone(traceRecord, NUM_RECORDS);
printf("Starting up...\n");
heap_trace_start(HEAP_TRACE_ALL);
heapUsedAtStart = heap_caps_get_free_size(MALLOC_CAP_8BIT);
printf("Heap free at start %d.\n", heapUsedAtStart);
heapUsed = heap_caps_get_free_size(MALLOC_CAP_8BIT);
mutex1 = xSemaphoreCreateMutex();
printf("Heap used by first mutex %d.\n", heapUsed - heap_caps_get_free_size(MALLOC_CAP_8BIT));
heapUsed = heap_caps_get_free_size(MALLOC_CAP_8BIT);
mutex2 = xSemaphoreCreateMutex();
printf("Heap used by second mutex %d.\n", heapUsed - heap_caps_get_free_size(MALLOC_CAP_8BIT));
heapUsed = heap_caps_get_free_size(MALLOC_CAP_8BIT);
vSemaphoreDelete(mutex1);
printf("Heap free'd after deleting just first mutex %d.\n", heap_caps_get_free_size(MALLOC_CAP_8BIT) - heapUsed);
heap_trace_stop();
heap_trace_dump();
if (!heap_caps_check_integrity_all(true)) {
printf("Heap is corrupt!\n");
}
heapUsed = heap_caps_get_free_size(MALLOC_CAP_8BIT);
printf("Heap used at end %d, therefore total heap used %d.\n", heapUsed, heapUsedAtStart - heapUsed);
while (1);
}
Code: Select all
Starting up...
Heap free at start 286244.
Heap used by first mutex 84.
Heap used by second mutex 84.
Heap free'd after deleting just first mutex 80.
2 allocations trace (10 entry buffer)
80 bytes (@ 0x3ffb98f4) allocated CPU 0 ccount 0x0518e10c caller 0x40087b06:0x40087d5b
freed by 0x400881f7:0x400e1878
80 bytes (@ 0x3ffb9948) allocated CPU 0 ccount 0x051f3ca4 caller 0x40087b06:0x40087d5b
80 bytes alive in trace (1/2 allocations)
total allocations 2 total frees 1
Heap used at end 286156, therefore total heap used 88.
Original post continues:
I'm adding memory leak checking to my tests, as measured by making calls to xPortGetFreeHeapSize() at the start and end of each test. In one particular test I have found that 40 bytes of heap are being "leaked" [see also a much simpler case of a similar problem in my reply below]. This test creates dynamic tasks and deletes them (blocking for the idle task to run after each deletion in order that resources can be cleaned-up) and installs and then uninstalls a pair of UART drivers that are connected back to back (though no characters are ever sent over either UART).
I have covered the intervening code in many more calls to xPortGetFreeHeapSize() but I am unable to get a consistent answer as to what's going on: basically blocks of four or eight bytes just seem to go missing. For instance I might create a mutex with a call to xSemaphoreCreateMutex(), costing 84 bytes (as measured by calls to xPortGetFreeHeapSize() either side of xSemaphoreCreateMutex()), but some time later when all my code is doing is deleting the mutex (no serial driver or other task [aside from idle] [should be] active at the time) with a call to vSemaphoreDelete() only 80 bytes come back (as measured by calls to xPortGetFreeHeapSize() either side of vSemaphoreDelete()).
I have run heap_trace in standalone/leak mode over this test and it only finds that 2 x 12 bytes have been allocated but not free()'d, both in get_desc_for_int()/esp_intr_alloc_intrstatus() at intr_alloc.c:230/intr_alloc.c:599, which I guess is the UART drivers doing something. It also says "total allocations 52 total frees 52". A total memory trace for the period is attached.
My question is: how can I find out where the other 16 bytes are going? And how can I get all 40 bytes back again?
The code that lies above the native ESP-IDF calls is also being run on NRF52 and STM32F4 and shows no memory leaks there, so whatever is going on must be connected with the underlying ESP32 code or how I'm using it. No tasks aside from idle and the main task are being run before or after the test. I'm not printf()ing anything other than integers. I have printf()'ed before this test starts so any initial stdio allocation for this task is not a part of the sums. This is on ESP-IDF release/v4.1 (573f5de99).