1Heap Memory Debugging 2===================== 3 4Overview 5-------- 6 7ESP-IDF integrates tools for requesting :ref:`heap information <heap-information>`, :ref:`detecting heap corruption <heap-corruption>`, and :ref:`tracing memory leaks <heap-tracing>`. These can help track down memory-related bugs. 8 9For general information about the heap memory allocator, see the :doc:`Heap Memory Allocation </api-reference/system/mem_alloc>` page. 10 11.. _heap-information: 12 13Heap Information 14---------------- 15 16To obtain information about the state of the heap: 17 18- :cpp:func:`xPortGetFreeHeapSize` is a FreeRTOS function which returns the number of free bytes in the (data memory) heap. This is equivalent to calling ``heap_caps_get_free_size(MALLOC_CAP_8BIT)``. 19- :cpp:func:`heap_caps_get_free_size` can also be used to return the current free memory for different memory capabilities. 20- :cpp:func:`heap_caps_get_largest_free_block` can be used to return the largest free block in the heap. This is the largest single allocation which is currently possible. Tracking this value and comparing to total free heap allows you to detect heap fragmentation. 21- :cpp:func:`xPortGetMinimumEverFreeHeapSize` and the related :cpp:func:`heap_caps_get_minimum_free_size` can be used to track the heap "low water mark" since boot. 22- :cpp:func:`heap_caps_get_info` returns a :cpp:class:`multi_heap_info_t` structure which contains the information from the above functions, plus some additional heap-specific data (number of allocations, etc.). 23- :cpp:func:`heap_caps_print_heap_info` prints a summary to stdout of the information returned by :cpp:func:`heap_caps_get_info`. 24- :cpp:func:`heap_caps_dump` and :cpp:func:`heap_caps_dump_all` will output detailed information about the structure of each block in the heap. Note that this can be large amount of output. 25 26 27.. _heap-corruption: 28 29Heap Corruption Detection 30------------------------- 31 32Heap corruption detection allows you to detect various types of heap memory errors: 33 34- Out of bounds writes & buffer overflow. 35- Writes to freed memory. 36- Reads from freed or uninitialized memory, 37 38Assertions 39^^^^^^^^^^ 40 41The heap implementation (``multi_heap.c``, etc.) includes a lot of assertions which will fail if the heap memory is corrupted. To detect heap corruption most effectively, ensure that assertions are enabled in the project configuration menu under ``Compiler options`` -> :ref:`CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL`. 42 43If a heap integrity assertion fails, a line will be printed like ``CORRUPT HEAP: multi_heap.c:225 detected at 0x3ffbb71c``. The memory address which is printed is the address of the heap structure which has corrupt content. 44 45It's also possible to manually check heap integrity by calling :cpp:func:`heap_caps_check_integrity_all` or related functions. This function checks all of requested heap memory for integrity, and can be used even if assertions are disabled. If the integrity check prints an error, it will also contain the address(es) of corrupt heap structures. 46 47Memory Allocation Failed Hook 48^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 49 50Users can use :cpp:func:`heap_caps_register_failed_alloc_callback` to register a callback that will be invoked every time a allocation 51operation fails. 52 53Additionaly user can enable a generation of a system abort if allocation operation fails by following the steps below: 54- In the project configuration menu, navigate to ``Component config`` -> ``Heap Memory Debugging`` and select ``Abort if memory allocation fails`` option (see :ref:`CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS`). 55 56The example below show how to register a allocation failure callback:: 57 58 #include "esp_heap_caps.h" 59 60 void heap_caps_alloc_failed_hook(size_t requested_size, uint32_t caps, const char *function_name) 61 { 62 printf("%s was called but failed to allocate %d bytes with 0x%X capabilities. \n",function_name, requested_size, caps); 63 } 64 65 void app_main() 66 { 67 ... 68 esp_err_t error = heap_caps_register_failed_alloc_callback(heap_caps_alloc_failed_hook); 69 ... 70 void *ptr = heap_caps_malloc(allocation_size, MALLOC_CAP_DEFAULT); 71 ... 72 } 73 74Finding Heap Corruption 75^^^^^^^^^^^^^^^^^^^^^^^ 76 77Memory corruption can be one of the hardest classes of bugs to find and fix, as one area of memory can be corrupted from a totally different place. Some tips: 78 79- A crash with a ``CORRUPT HEAP:`` message will usually include a stack trace, but this stack trace is rarely useful. The crash is the symptom of memory corruption when the system realises the heap is corrupt, but usually the corruption happened elsewhere and earlier in time. 80- Increasing the Heap memory debugging `Configuration`_ level to "Light impact" or "Comprehensive" can give you a more accurate message with the first corrupt memory address. 81- Adding regular calls to :cpp:func:`heap_caps_check_integrity_all` or :cpp:func:`heap_caps_check_integrity_addr` in your code will help you pin down the exact time that the corruption happened. You can move these checks around to "close in on" the section of code that corrupted the heap. 82- Based on the memory address which is being corrupted, you can use :ref:`JTAG debugging <jtag-debugging-introduction>` to set a watchpoint on this address and have the CPU halt when it is written to. 83- If you don't have JTAG, but you do know roughly when the corruption happens, then you can set a watchpoint in software just beforehand via :cpp:func:`esp_cpu_set_watchpoint`. A fatal exception will occur when the watchpoint triggers. For example ``esp_cpu_set_watchpoint(0, (void *)addr, 4, ESP_WATCHPOINT_STORE``. Note that watchpoints are per-CPU and are set on the current running CPU only, so if you don't know which CPU is corrupting memory then you will need to call this function on both CPUs. 84- For buffer overflows, `heap tracing`_ in ``HEAP_TRACE_ALL`` mode lets you see which callers are allocating which addresses from the heap. See `Heap Tracing To Find Heap Corruption`_ for more details. If you can find the function which allocates memory with an address immediately before the address which is corrupted, this will probably be the function which overflows the buffer. 85- Calling :cpp:func:`heap_caps_dump` or :cpp:func:`heap_caps_dump_all` can give an indication of what heap blocks are surrounding the corrupted region and may have overflowed/underflowed/etc. 86 87Configuration 88^^^^^^^^^^^^^ 89 90Temporarily increasing the heap corruption detection level can give more detailed information about heap corruption errors. 91 92In the project configuration menu, under ``Component config`` there is a menu ``Heap memory debugging``. The setting :ref:`CONFIG_HEAP_CORRUPTION_DETECTION` can be set to one of three levels: 93 94Basic (no poisoning) 95++++++++++++++++++++ 96 97This is the default level. No special heap corruption features are enabled, but provided assertions are enabled (the default configuration) then a heap corruption error will be printed if any of the heap's internal data structures appear overwritten or corrupted. This usually indicates a buffer overrun or out of bounds write. 98 99If assertions are enabled, an assertion will also trigger if a double-free occurs (the same memory is freed twice). 100 101Calling :cpp:func:`heap_caps_check_integrity` in Basic mode will check the integrity of all heap structures, and print errors if any appear to be corrupted. 102 103Light Impact 104++++++++++++ 105 106At this level, heap memory is additionally "poisoned" with head and tail "canary bytes" before and after each block which is allocated. If an application writes outside the bounds of allocated buffers, the canary bytes will be corrupted and the integrity check will fail. 107 108The head canary word is 0xABBA1234 (3412BAAB in byte order), and the tail canary word is 0xBAAD5678 (7856ADBA in byte order). 109 110"Basic" heap corruption checks can also detect most out of bounds writes, but this setting is more precise as even a single byte overrun can be detected. With Basic heap checks, the number of overrun bytes before a failure is detected will depend on the properties of the heap. 111 112Enabling "Light Impact" checking increases memory usage, each individual allocation will use 9 to 12 additional bytes of memory (depending on alignment). 113 114Each time ``free()`` is called in Light Impact mode, the head and tail canary bytes of the buffer being freed are checked against the expected values. 115 116When :cpp:func:`heap_caps_check_integrity` is called, all allocated blocks of heap memory have their canary bytes checked against the expected values. 117 118In both cases, the check is that the first 4 bytes of an allocated block (before the buffer returned to the user) should be the word 0xABBA1234. Then the last 4 bytes of the allocated block (after the buffer returned to the user) should be the word 0xBAAD5678. 119 120Different values usually indicate buffer underrun or overrun, respectively. 121 122 123Comprehensive 124+++++++++++++ 125 126This level incorporates the "light impact" detection features plus additional checks for uninitialised-access and use-after-free bugs. In this mode, all freshly allocated memory is filled with the pattern 0xCE, and all freed memory is filled with the pattern 0xFE. 127 128Enabling "Comprehensive" detection has a substantial runtime performance impact (as all memory needs to be set to the allocation patterns each time a malloc/free completes, and the memory also needs to be checked each time.) However it allows easier detection of memory corruption bugs which are much more subtle to find otherwise. It is recommended to only enable this mode when debugging, not in production. 129 130Crashes in Comprehensive Mode 131~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 132 133If an application crashes reading/writing an address related to 0xCECECECE in Comprehensive mode, this indicates it has read uninitialized memory. The application should be changed to either use calloc() (which zeroes memory), or initialize the memory before using it. The value 0xCECECECE may also be seen in stack-allocated automatic variables, because in IDF most task stacks are originally allocated from the heap and in C stack memory is uninitialized by default. 134 135If an application crashes and the exception register dump indicates that some addresses or values were 0xFEFEFEFE, this indicates it is reading heap memory after it has been freed (a "use after free bug".) The application should be changed to not access heap memory after it has been freed. 136 137If a call to malloc() or realloc() causes a crash because it expected to find the pattern 0xFEFEFEFE in free memory and a different pattern was found, then this indicates the app has a use-after-free bug where it is writing to memory which has already been freed. 138 139Manual Heap Checks in Comprehensive Mode 140~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 141 142Calls to :cpp:func:`heap_caps_check_integrity` may print errors relating to 0xFEFEFEFE, 0xABBA1234 or 0xBAAD5678. In each case the checker is expecting to find a given pattern, and will error out if this is not found: 143 144- For free heap blocks, the checker expects to find all bytes set to 0xFE. Any other values indicate a use-after-free bug where free memory has been incorrectly overwritten. 145- For allocated heap blocks, the behaviour is the same as for `Light Impact` mode. The canary bytes 0xABBA1234 and 0xBAAD5678 are checked at the head and tail of each allocated buffer, and any variation indicates a buffer overrun/underrun. 146 147.. _heap-task-tracking: 148 149Heap Task Tracking 150------------------ 151 152Heap Task Tracking can be used to get per task info for heap memory allocation. 153Application has to specify the heap capabilities for which the heap allocation is to be tracked. 154 155Example code is provided in :example:`system/heap_task_tracking` 156 157.. _heap-tracing: 158 159Heap Tracing 160------------ 161 162Heap Tracing allows tracing of code which allocates/frees memory. Two tracing modes are supported: 163 164- Standalone. In this mode trace data are kept on-board, so the size of gathered information is limited by the buffer assigned for that purposes. Analysis is done by the on-board code. There are a couple of APIs available for accessing and dumping collected info. 165- Host-based. This mode does not have the limitation of the standalone mode, because trace data are sent to the host over JTAG connection using app_trace library. Later on they can be analysed using special tools. 166 167Heap tracing can perform two functions: 168 169- Leak checking: find memory which is allocated and never freed. 170- Heap use analysis: show all functions that are allocating/freeing memory while the trace is running. 171 172How To Diagnose Memory Leaks 173^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 174 175If you suspect a memory leak, the first step is to figure out which part of the program is leaking memory. Use the :cpp:func:`xPortGetFreeHeapSize`, :cpp:func:`heap_caps_get_free_size`, or :ref:`related functions <heap-information>` to track memory use over the life of the application. Try to narrow the leak down to a single function or sequence of functions where free memory always decreases and never recovers. 176 177 178Standalone Mode 179+++++++++++++++ 180 181Once you've identified the code which you think is leaking: 182 183- In the project configuration menu, navigate to ``Component settings`` -> ``Heap Memory Debugging`` -> ``Heap tracing`` and select ``Standalone`` option (see :ref:`CONFIG_HEAP_TRACING_DEST`). 184- Call the function :cpp:func:`heap_trace_init_standalone` early in the program, to register a buffer which can be used to record the memory trace. 185- Call the function :cpp:func:`heap_trace_start` to begin recording all mallocs/frees in the system. Call this immediately before the piece of code which you suspect is leaking memory. 186- Call the function :cpp:func:`heap_trace_stop` to stop the trace once the suspect piece of code has finished executing. 187- Call the function :cpp:func:`heap_trace_dump` to dump the results of the heap trace. 188 189An example:: 190 191 #include "esp_heap_trace.h" 192 193 #define NUM_RECORDS 100 194 static heap_trace_record_t trace_record[NUM_RECORDS]; // This buffer must be in internal RAM 195 196 ... 197 198 void app_main() 199 { 200 ... 201 ESP_ERROR_CHECK( heap_trace_init_standalone(trace_record, NUM_RECORDS) ); 202 ... 203 } 204 205 void some_function() 206 { 207 ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_LEAKS) ); 208 209 do_something_you_suspect_is_leaking(); 210 211 ESP_ERROR_CHECK( heap_trace_stop() ); 212 heap_trace_dump(); 213 ... 214 } 215 216The output from the heap trace will look something like this: 217 218.. only:: CONFIG_IDF_TARGET_ARCH_XTENSA 219 220 :: 221 222 2 allocations trace (100 entry buffer) 223 32 bytes (@ 0x3ffaf214) allocated CPU 0 ccount 0x2e9b7384 caller 0x400d276d:0x400d27c1 224 0x400d276d: leak_some_memory at /path/to/idf/examples/get-started/blink/main/./blink.c:27 225 226 0x400d27c1: blink_task at /path/to/idf/examples/get-started/blink/main/./blink.c:52 227 228 8 bytes (@ 0x3ffaf804) allocated CPU 0 ccount 0x2e9b79c0 caller 0x400d2776:0x400d27c1 229 0x400d2776: leak_some_memory at /path/to/idf/examples/get-started/blink/main/./blink.c:29 230 231 0x400d27c1: blink_task at /path/to/idf/examples/get-started/blink/main/./blink.c:52 232 233 40 bytes 'leaked' in trace (2 allocations) 234 total allocations 2 total frees 0 235 236.. only:: CONFIG_IDF_TARGET_ARCH_RISCV 237 238 :: 239 240 2 allocations trace (100 entry buffer) 241 32 bytes (@ 0x3ffaf214) allocated CPU 0 ccount 0x2e9b7384 caller 242 8 bytes (@ 0x3ffaf804) allocated CPU 0 ccount 0x2e9b79c0 caller 243 40 bytes 'leaked' in trace (2 allocations) 244 total allocations 2 total frees 0 245 246(Above example output is using :doc:`IDF Monitor </api-guides/tools/idf-monitor>` to automatically decode PC addresses to their source files & line number.) 247 248The first line indicates how many allocation entries are in the buffer, compared to its total size. 249 250In ``HEAP_TRACE_LEAKS`` mode, for each traced memory allocation which has not already been freed a line is printed with: 251 252.. list:: 253 254 - ``XX bytes`` is number of bytes allocated 255 - ``@ 0x...`` is the heap address returned from malloc/calloc. 256 - ``CPU x`` is the CPU (0 or 1) running when the allocation was made. 257 - ``ccount 0x...`` is the CCOUNT (CPU cycle count) register value when the allocation was mode. Is different for CPU 0 vs CPU 1. 258 :CONFIG_IDF_TARGET_ARCH_XTENSA: - ``caller 0x...`` gives the call stack of the call to malloc()/free(), as a list of PC addresses. These can be decoded to source files and line numbers, as shown above. 259 260.. only:: not CONFIG_IDF_TARGET_ARCH_RISCV 261 262 The depth of the call stack recorded for each trace entry can be configured in the project configuration menu, under ``Heap Memory Debugging`` -> ``Enable heap tracing`` -> ``Heap tracing stack depth``. Up to 10 stack frames can be recorded for each allocation (the default is 2). Each additional stack frame increases the memory usage of each ``heap_trace_record_t`` record by eight bytes. 263 264Finally, the total number of 'leaked' bytes (bytes allocated but not freed while trace was running) is printed, and the total number of allocations this represents. 265 266A warning will be printed if the trace buffer was not large enough to hold all the allocations which happened. If you see this warning, consider either shortening the tracing period or increasing the number of records in the trace buffer. 267 268 269Host-Based Mode 270+++++++++++++++ 271 272Once you've identified the code which you think is leaking: 273 274- In the project configuration menu, navigate to ``Component settings`` -> ``Heap Memory Debugging`` -> :ref:`CONFIG_HEAP_TRACING_DEST` and select ``Host-Based``. 275- In the project configuration menu, navigate to ``Component settings`` -> ``Application Level Tracing`` -> :ref:`CONFIG_APPTRACE_DESTINATION` and select ``Trace memory``. 276- In the project configuration menu, navigate to ``Component settings`` -> ``Application Level Tracing`` -> ``FreeRTOS SystemView Tracing`` and enable :ref:`CONFIG_APPTRACE_SV_ENABLE`. 277- Call the function :cpp:func:`heap_trace_init_tohost` early in the program, to initialize JTAG heap tracing module. 278- Call the function :cpp:func:`heap_trace_start` to begin recording all mallocs/frees in the system. Call this immediately before the piece of code which you suspect is leaking memory. 279 In host-based mode argument to this function is ignored and heap tracing module behaves like ``HEAP_TRACE_ALL`` was passed: all allocations and deallocations are sent to the host. 280- Call the function :cpp:func:`heap_trace_stop` to stop the trace once the suspect piece of code has finished executing. 281 282An example:: 283 284 #include "esp_heap_trace.h" 285 286 ... 287 288 void app_main() 289 { 290 ... 291 ESP_ERROR_CHECK( heap_trace_init_tohost() ); 292 ... 293 } 294 295 void some_function() 296 { 297 ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_LEAKS) ); 298 299 do_something_you_suspect_is_leaking(); 300 301 ESP_ERROR_CHECK( heap_trace_stop() ); 302 ... 303 } 304 305To gather and analyse heap trace do the following on the host: 306 3071. Build the program and download it to the target as described in :ref:`Getting Started Guide <get-started-build>`. 308 3092. Run OpenOCD (see :doc:`JTAG Debugging </api-guides/jtag-debugging/index>`). 310 311.. note:: 312 313 In order to use this feature you need OpenOCD version `v0.10.0-esp32-20181105` or later. 314 3153. You can use GDB to start and/or stop tracing automatically. To do this you need to prepare special ``gdbinit`` file:: 316 317 target remote :3333 318 319 mon reset halt 320 flushregs 321 322 tb heap_trace_start 323 commands 324 mon esp sysview start file:///tmp/heap.svdat 325 c 326 end 327 328 tb heap_trace_stop 329 commands 330 mon esp sysview stop 331 end 332 333 c 334 335Using this file GDB will connect to the target, reset it, and start tracing when program hits breakpoint at :cpp:func:`heap_trace_start`. Trace data will be saved to ``/tmp/heap_log.svdat``. Tracing will be stopped when program hits breakpoint at :cpp:func:`heap_trace_stop`. 336 3374. Run GDB using the following command ``{IDF_TARGET_TOOLCHAIN_PREFIX}-gdb -x gdbinit </path/to/program/elf>`` 338 3395. Quit GDB when program stops at :cpp:func:`heap_trace_stop`. Trace data are saved in ``/tmp/heap.svdat`` 340 3416. Run processing script ``$IDF_PATH/tools/esp_app_trace/sysviewtrace_proc.py -p -b </path/to/program/elf> /tmp/heap_log.svdat`` 342 343The output from the heap trace will look something like this:: 344 345 Parse trace from '/tmp/heap.svdat'... 346 Stop parsing trace. (Timeout 0.000000 sec while reading 1 bytes!) 347 Process events from '['/tmp/heap.svdat']'... 348 [0.002244575] HEAP: Allocated 1 bytes @ 0x3ffaffd8 from task "alloc" on core 0 by: 349 /home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:47 350 /home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1) 351 352 [0.002258425] HEAP: Allocated 2 bytes @ 0x3ffaffe0 from task "alloc" on core 0 by: 353 /home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:48 354 /home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1) 355 356 [0.002563725] HEAP: Freed bytes @ 0x3ffaffe0 from task "free" on core 0 by: 357 /home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:31 (discriminator 9) 358 /home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1) 359 360 [0.002782950] HEAP: Freed bytes @ 0x3ffb40b8 from task "main" on core 0 by: 361 /home/user/projects/esp/esp-idf/components/freertos/tasks.c:4590 362 /home/user/projects/esp/esp-idf/components/freertos/tasks.c:4590 363 364 [0.002798700] HEAP: Freed bytes @ 0x3ffb50bc from task "main" on core 0 by: 365 /home/user/projects/esp/esp-idf/components/freertos/tasks.c:4590 366 /home/user/projects/esp/esp-idf/components/freertos/tasks.c:4590 367 368 [0.102436025] HEAP: Allocated 2 bytes @ 0x3ffaffe0 from task "alloc" on core 0 by: 369 /home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:47 370 /home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1) 371 372 [0.102449800] HEAP: Allocated 4 bytes @ 0x3ffaffe8 from task "alloc" on core 0 by: 373 /home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:48 374 /home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1) 375 376 [0.102666150] HEAP: Freed bytes @ 0x3ffaffe8 from task "free" on core 0 by: 377 /home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:31 (discriminator 9) 378 /home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1) 379 380 [0.202436200] HEAP: Allocated 3 bytes @ 0x3ffaffe8 from task "alloc" on core 0 by: 381 /home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:47 382 /home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1) 383 384 [0.202451725] HEAP: Allocated 6 bytes @ 0x3ffafff0 from task "alloc" on core 0 by: 385 /home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:48 386 /home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1) 387 388 [0.202667075] HEAP: Freed bytes @ 0x3ffafff0 from task "free" on core 0 by: 389 /home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:31 (discriminator 9) 390 /home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1) 391 392 [0.302436000] HEAP: Allocated 4 bytes @ 0x3ffafff0 from task "alloc" on core 0 by: 393 /home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:47 394 /home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1) 395 396 [0.302451475] HEAP: Allocated 8 bytes @ 0x3ffb40b8 from task "alloc" on core 0 by: 397 /home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:48 398 /home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1) 399 400 [0.302667500] HEAP: Freed bytes @ 0x3ffb40b8 from task "free" on core 0 by: 401 /home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:31 (discriminator 9) 402 /home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1) 403 404 Processing completed. 405 Processed 1019 events 406 =============== HEAP TRACE REPORT =============== 407 Processed 14 heap events. 408 [0.002244575] HEAP: Allocated 1 bytes @ 0x3ffaffd8 from task "alloc" on core 0 by: 409 /home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:47 410 /home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1) 411 412 [0.102436025] HEAP: Allocated 2 bytes @ 0x3ffaffe0 from task "alloc" on core 0 by: 413 /home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:47 414 /home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1) 415 416 [0.202436200] HEAP: Allocated 3 bytes @ 0x3ffaffe8 from task "alloc" on core 0 by: 417 /home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:47 418 /home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1) 419 420 [0.302436000] HEAP: Allocated 4 bytes @ 0x3ffafff0 from task "alloc" on core 0 by: 421 /home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:47 422 /home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1) 423 424 Found 10 leaked bytes in 4 blocks. 425 426Heap Tracing To Find Heap Corruption 427^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 428 429Heap tracing can also be used to help track down heap corruption. When a region in heap is corrupted, it may be from some other part of the program which allocated memory at a nearby address. 430 431If you have some idea at what time the corruption occurred, enabling heap tracing in ``HEAP_TRACE_ALL`` mode allows you to record all of the functions which allocated memory, and the addresses of the allocations. 432 433Using heap tracing in this way is very similar to memory leak detection as described above. For memory which is allocated and not freed, the output is the same. However, records will also be shown for memory which has been freed. 434 435Performance Impact 436^^^^^^^^^^^^^^^^^^ 437 438Enabling heap tracing in menuconfig increases the code size of your program, and has a very small negative impact on performance of heap allocation/free operations even when heap tracing is not running. 439 440When heap tracing is running, heap allocation/free operations are substantially slower than when heap tracing is stopped. Increasing the depth of stack frames recorded for each allocation (see above) will also increase this performance impact. 441 442False-Positive Memory Leaks 443^^^^^^^^^^^^^^^^^^^^^^^^^^^ 444 445Not everything printed by :cpp:func:`heap_trace_dump` is necessarily a memory leak. Among things which may show up here, but are not memory leaks: 446 447- Any memory which is allocated after :cpp:func:`heap_trace_start` but then freed after :cpp:func:`heap_trace_stop` will appear in the leak dump. 448- Allocations may be made by other tasks in the system. Depending on the timing of these tasks, it's quite possible this memory is freed after :cpp:func:`heap_trace_stop` is called. 449- The first time a task uses stdio - for example, when it calls ``printf()`` - a lock (RTOS mutex semaphore) is allocated by the libc. This allocation lasts until the task is deleted. 450- Certain uses of ``printf()``, such as printing floating point numbers, will allocate some memory from the heap on demand. These allocations last until the task is deleted. 451- The Bluetooth, WiFi, and TCP/IP libraries will allocate heap memory buffers to handle incoming or outgoing data. These memory buffers are usually short lived, but some may be shown in the heap leak trace if the data was received/transmitted by the lower levels of the network while the leak trace was running. 452- TCP connections will continue to use some memory after they are closed, because of the ``TIME_WAIT`` state. After the ``TIME_WAIT`` period has completed, this memory will be freed. 453 454One way to differentiate between "real" and "false positive" memory leaks is to call the suspect code multiple times while tracing is running, and look for patterns (multiple matching allocations) in the heap trace output. 455 456API Reference - Heap Tracing 457---------------------------- 458 459.. include-build-file:: inc/esp_heap_trace.inc 460