Dynamic Memory Allocation: Justifiably Taboo?
Fault-tolerant systems should employ custom memory allocators that are more precisely suited to the application’s specific allocation patterns. Custom memory managers presented in the paper include block, stack, bitmap and thread-local allocators. The solutions presented retain the power and flexibility of dynamic memory management while mitigating common risks such as fragmentation and memory leaks, and improving efficiency and performance.
Users have different quality expectations for embedded systems than for business and desktop applications. We wouldn’t tolerate our cell phone or set-top box failing regularly, or even once in a while. And some embedded systems, such as the avionics that enable a jet to fly safely, are expected to be even more dependable: they must be fail-safe. In short, the effect of errors, unpredictable behavior and degraded performance in embedded systems ranges from a bad user experience and eroded customer loyalty, to potential loss of life – none of which is acceptable to organizations releasing this technology out into the world.
So what makes embedded applications, ranging from consumer electronics to mission critical aerospace and industrial control, more dependable? Apart from reliable hardware platforms, it is the software components of those systems: the operating system, middleware and applications. In embedded environments, these components should be immune from crashes. And if an application does fail, the failure shouldn’t affect other applications or the operating system. In an embedded setting, this requirement is not always so easy to satisfy, because the applications are often implemented as separate tasks that run within the same address space. Finally, the operating system and application software should not introduce unpredictable latencies. That is, they should exhibit predictable performance.
Memory Management and Performance, Predictability and Resilience
Embedded systems’ reliability imperative requires a close examination of all aspects of software development, and how approaches to concepts such as scheduling, synchronization across multiple tasks and processes, locking strategies, deadline management, and memory management affect quality. For example, unpredictable latencies can be introduced by techniques such as message passing or garbage collection. Such approaches should be avoided or their unpredictable latencies mitigated.
This paper focuses on the fundamental programming concept of memory management. Safe, predictable and efficient program execution is often the result of sound memory management, while the wrong practices, or inattention to memory management, can result in slow and/or unpredictable performance (which may be a result of memory fragmentation), as well as instability or failure due to memory leaks.
The impact of badly written or improperly used memory management can vary in severity. Less severe might mean slow or unpredictable performance in specific circumstances, such as when an application is moved from a single-core to a multi-core environment. At the more severe end of the spectrum, a high level of memory fragmentation may increasingly degrade performance, resulting finally in application failure. Even more severe could be system-wide instability or failure due to memory leaks.
Software designers who develop safety-critical applications for airborne systems are well aware of the risks of unsound memory management. Industry norms dictate that safety-critical applications should avoid using techniques that could introduce instability. Those readers involved in creating airborne systems should be familiar with the DO-178B standard, used by the U.S. Federal Aviation Administration to certify avionics software. Among other strictures, the DO-178B document states:
“Software Design Standards should include…constraints on design, for example, exclusion of recursion, dynamic objects, data aliases, and compacted expressions.”
[DO-178B, Software Considerations in Airborne Systems and Equipment Certification, RTCA, Inc. (jointly developed with European Organisation for Civil Aviation Equipment, EUROCAE)]
“Dynamic Objects” in this quote refers to objects created in the application through dynamic memory allocation, a technique in many programming languages, including C, in which system memory is allocated to processes on an as-needed basis at run-time.