EmbeddedRelated.com

Memory Leak

Category: Memory | Also known as: memory leaks

A memory leak occurs when dynamically allocated memory is no longer reachable by the program but has not been freed, causing the allocator to be unable to reclaim it for future use. More broadly, the term also covers memory that is technically reachable but effectively abandoned -- held by a reference that will never be used to free it. Over time, repeated leaks reduce the pool of available memory until allocations fail or the system crashes.

In practice

In embedded systems that use dynamic allocation (malloc/free or equivalents), a leak typically happens when a code path exits without freeing a previously allocated buffer, when a pointer is overwritten before the original block is freed, or when ownership of an allocation is ambiguous across module boundaries. On resource-constrained targets with small heaps (a few kilobytes on many Cortex-M0 or 8-bit MCU designs), even a small persistent leak can exhaust memory within minutes or hours of operation.

Many embedded projects avoid dynamic allocation entirely to eliminate heap-based leaks, favoring static allocation or fixed memory pools. When dynamic allocation is used, common mitigation strategies include pairing every allocation site with an explicit free, using RAII patterns in C++, and establishing clear ownership rules. The blog post "Global Variables vs. Safe Software" touches on why disciplined memory ownership matters in embedded contexts.

Detecting leaks in embedded targets is harder than on hosted systems because standard tools like Valgrind do not run on bare-metal firmware, though some detection is still possible through simulators, host-based unit tests, or target-side instrumentation. Instrumentation approaches, such as wrapping malloc/free to record outstanding allocations and their sizes, can help. The blog post "How to make a heap profiler" describes one practical implementation of this technique. Tracking the high-water mark of heap usage over long runtimes can also surface slow leaks that would not appear during short test runs.

A subtler form of resource leak in embedded firmware involves losing track of statically allocated resources rather than heap blocks: for example, filling a finite pool of message buffers without ever returning them. These behave identically to heap leaks in their effect -- and are sometimes informally called memory leaks -- but are more precisely described as resource leaks or pool exhaustion. They are often overlooked because developers associate "memory leak" exclusively with malloc.

Frequently asked

Does avoiding malloc/free eliminate memory leaks in embedded firmware?
It eliminates heap-based leaks, which are the most common form. However, firmware that uses fixed-size memory pools, ring buffers, or other manually managed static resources can still experience equivalent leaks if items are acquired but never returned. The underlying problem -- acquiring a resource and losing the ability to release it -- is not unique to the heap.
How can I detect a memory leak on a bare-metal target with no OS?
Common approaches include wrapping malloc and free with instrumentation that tracks outstanding allocation counts and total bytes, then exposing that data over a debug UART or JTAG. Logging the heap free space at regular intervals and watching for a monotonically decreasing trend over a long soak run is another practical method. The blog post 'How to make a heap profiler' covers one implementation of this kind of instrumentation.
Can a memory leak occur in a system that runs for only a short time?
A leak will not cause a failure if the total leaked memory never exhausts the available pool within the system's operating lifetime. In practice this means short-lived or infrequently triggered code paths can hide leaks during testing that only manifest after days or weeks of continuous operation -- a common scenario for embedded devices in the field.
Are memory leaks possible in C++ firmware using RAII?
RAII significantly reduces leak risk because destructors release resources automatically when objects go out of scope. Leaks can still occur if raw pointers are used alongside smart pointers, if ownership is transferred incorrectly, or if objects are kept alive longer than intended (for example, held in a container that is never cleared). Using std::unique_ptr or std::shared_ptr consistently removes most of the manual bookkeeping that leads to leaks.
How is a memory leak different from heap fragmentation?
A memory leak means allocated blocks are never freed, so usable heap capacity shrinks permanently. Heap fragmentation means blocks are freed but the free space is split into small non-contiguous chunks that cannot satisfy a larger allocation request, even though the total free bytes would be sufficient in aggregate. Both can cause allocation failures, but they have different root causes and different remedies.

Differentiators vs similar concepts

Memory leak vs. heap fragmentation: a leak permanently reduces available memory because allocations are never freed; fragmentation leaves memory technically free but unusable for larger requests due to non-contiguous free blocks. Both can exhaust usable heap space, but fragmentation can occur even in leak-free code with frequent mixed-size alloc/free cycles.