Memory Management In Embedded Systems
Introduction
Embedded systems software has many aspects which distinguish it from other
types of software systems. It is difficult to understate the importance
of memory management in these types of systems. The fact that embedded
systems should be able to operate indefinitely imposes a set of requirements
that are not as important for other types of software systems. Forces
that degrade system resources over time are of particular interest in systems
that execute over a long period of time.
Entropy
Heap Fragmentation
Programs, which have a limited execution interval, either by design or
by user acceptance, are not subject to the same constraints imposed upon
embedded applications. Batch oriented aapplications, such as compilers,
run for a limited time and are subsequently restarted with a bright shiny
new heap upon their next invocation. Interactive programs, or the platform
upon which they run, are restarted relatively frequently providing an oportunity
for rotting heap structures to be renewed. Although this is not a desirable
feature, it has become widely accepted by users that this is simply a reality
with which they must live.
Traditional dynamic memory management operations such as malloc()/free()
and new/delete, while superficially easy to use, mask potential problems
and oversimplify issues surrounding memory management that results in many
insidious side effects.
Unless an application executes in a memory space that is constrained
relative to the needs of the program, or the program is especially long
running, or if the program allocates and frees dynamic memory resources
of varying sizes at a high frequency, it is unlikely to encounter the effects
of heap fragmentation. Furthermore, when the effects of heap fragmentation
are encountered, it is much more common to relieve the symptoms than to
solve the problem. The most common solutions are to require the user to
have more memory, or to suggest that the customer restart the program or
the system upon which the program executes. Sound familiar? Unfortunately,
this type of solution only reduces the frequency of failure to an "acceptable"
threshold.
Embedded systems are long running programs that typically execute in
a resource (e.g. memory) constrained environment. Periodically rebooting
systems, either manually or automatically, not only may tarnish the reputation
of the system's vendor, but may also endanger lives either directly or
indirectly. Thus, it is important that we solve the underlying problem
and not simply attempt to reduce its frequency.
Memory Leaks
Another source of entropy in memory management is the so called memory
leak. Software designs that have incosistent or ad-hoc dynamic memory management
strategies are subject to program errors where dynamically allocated memory
resources are not released. The result is that over time, the application
can no longer obtain the memory resources it needs to operate.
Since the effects of memory leaks can take a long period of time before
they manifest themselves in a way that indicates a failure, such software
defects may remain latent until encountered in a customer installation.
Find these defects can be quite difficult, and repairing the defect in
one place can cause a failure in another part of the program where the
assumptions about the responsiblity for freeing the allocated memory were
different.
It is for this reason that we recommend a design rule in which the client
owns and manages its own memory resources, and is responsible for both
the allocation and deallocation of its memory. Notice that this implies
that memory should never be allocated by one thread and subsequently freed
by another thread, except by design exception.
Determinism
Allocation Times
Real-time systems are embedded systems with time deadlines and behaviors
that are sensitive to execution timing. Heap fragmentation .
Resource Availability
Efficiency
Polling For Memory
Another problem with traditional memory managment operations is that they
are not designed for an event driven environment. There is no means for
notifying the program when memory is available. This leaves the designer
with little choice but to poll for available memory (evil), or simply fail.
While either of these may be tolerated in other software systems, they
are simply not acceptable in a system with limited processor bandwidth
and high availability requirements.
mike@mnmoran.org