Analyzing heap memory usage

Updated: October 26, 2022

The IDE offers several ways to analyze an application's heap memory usage. You can view realtime heap statistics, run analysis tools to track heap activity, and use the libc API to read heap information.

Some tools provide high-level data such as total, used, and free heap space and have low overhead and setup cost. Other tools provide detailed heap information such as allocation counts for specific block size ranges but require more configuration and impose more overhead. Generally, you should try using the heap analysis tools in the following order:
  1. System Information

    In the QNX System Information perspective, you can monitor the heap usage for a particular process through the Malloc Information view. Using the debugger, you can stop execution at interesting places in the code and see which pointers have new values (addresses). If you then switch to the Memory Information view, you can see if the segments containing those addresses have grown.

    This is the best tool to use first because you can switch to this perspective at any time to see the statistics. You don't need to reconfigure, recompile, or relaunch your application, and there's no application overhead because the statistics come from the general-purpose process-level allocator.

  2. Memory Analysis

    This tool displays data reported by the debug allocation library (librcheck) as the program runs, providing you with realtime statistics about a process's dynamic memory events and changes in its heap usage.

    This tool has an easy setup and imposes less overhead than other analysis tools but requires you to relaunch the application with the tool enabled.

    Note: The librcheck library tracks and analyzes heap managed by the dynamic allocation library only (malloc and its related functions). QNX processes might have heap that is not managed this way (e.g., allocated by a direct mmap() call) and is tracked or analyzed by this tool.
  3. Valgrind Massif

    Valgrind Massif is designed for heap analysis. This tool can tell you more than Memory Analysis; for example, it reports the peak in heap usage and provides better backtracing details.

    You don't need to recompile the application but you do need to configure Massif through the launch configuration. A drawback to using Valgrind is that it reports the results only when the program terminates, so you can't view memory usage in real time. Also, Massif imposes significantly more overhead than Memory Analysis.

  4. Application Profiler

    This tool parses the profiling data generated when an instrumented binary is run. In the launch configuration, you can specify heap memory as the profiling metric to make the IDE display the program's heap usage by function.

    Profiling has a higher setup cost than other analysis strategies because you must compile the project with the correct flags and relaunch it. The benefit is that the Application Profiler presents the heap data in an easy-to-read format and lets you compare the results from different sessions.

  5. The libc allocator API

    If you're comfortable using the libc allocator API, you can read the fields in the _malloc_stats structure to learn the used heap size, number of allocations, block overhead, and more.

    To use this API effectively, though, you must know the code well enough to determine suitable places for querying and outputting the heap statistics. Also, you must rebuild and relaunch the application to start outputting them.

You must run a binary built with debug information so the active tool can match binary instructions with lines of code and display the symbols (i.e., backtrace) in the results. To see symbols for shared libraries, your host machine must store debug versions of these libraries. Any binary with debug information has a bug icon (Icon: Small blue bug) next to its name in the Project Explorer. The binary selected for running when you launch a project depends on the launch configuration settings.