Pros and Cons of the various Memory Allocation Strategies
In C++ you have the choice between various memory allocation strategies. In addition to the frequently used dynamic memory allocation, you have the stack allocation. But you can preallocate the memory at the start time of your program. This can be a fixed-sized block or one or more memory pools. Each of these strategies has its pros and cons. One, I will answer in this post.
In the last post, I presented four typical strategies for managing memory. With this post, I will go one step further by presenting the differences in a table. Before I do this, I will define the criteria which are the base for my comparison.
The criteria
Fragmentation
Internal and external fragmentation are two significant issues of dynamic memory allocation and, therefore, for memory pools.
Internal fragmentation An object needs not to have the whole memory area that was reserved for it.
External fragmentation The unused memory between the objects is too small to be used for new objects.
Interestingly, a system optimized for internal fragmentations often has issues with external fragmentation. This also holds the other way around. The internal fragmentation is less the better the memory area fits the object. The consequence is that the object sizes are quite irregular, and you can not efficiently use the available memory. If you create equally sized memory areas for each object, the internal memory fragmentation will increase because you typically put the objects in oversized memory blocks.
One solution to the problem is to adjust the memory blocks to the object sizes and to move the memory blocks if needed. Therefore, the system is optimized for internal and external fragmentation. But this contradicts the temporal predictability of the memory allocation because it requires extra effort at runtime.
Modernes C++ Mentoring
Do you want to stay informed: Subscribe.
Memory exhaustion
The significant advantage of dynamic memory allocation is that the sheer amount of memory seems unlimited. This observation does not hold for a fixed memory block allocated at the program’s start time or for the stack.
Memory release
If I ignore smart pointers like std::unique_ptr or std::shared_ptr or the Boehm garbage collector, I have to explicitly release the memory in case of dynamic memory allocation or pool allocation. This will not hold for the stack. In the case of stack allocation, the C++ runtime automatically releases the memory; when allocating a fixed-sized block, the memory will usually not be released.
You will get memory leaks if you don’t release the memory.
Memory leaks
Stack allocation is, per see, free of memory leaks. This will not hold for the other three memory allocations. In particular, memory leaks are a big concern of dynamic memory allocation and memory pools.
Predictability
Predictability is a big issue in such applications that deal with hard real-time requirements. That means, in particular, there are time windows in which an operation must be performed. This kind of guarantee can not be given by dynamic memory allocation. For example, the memory may be fragmented. Therefore, dynamic memory allocation is often no option in an embedded system driven by real-time requirements. The restriction holds not for the three other ways to allocate memory. They have deterministic temporal behavior.
Ease of use
From the user’s perspective, each of the four presented memory allocations has pros and cons. Therefore, in the case of dynamic memory allocation and memory pool, the programmer must manage the memory. He has to call delete or free explicitly. This is contrary to a fixed-sized memory block or the stack. But there are other cons for both.
If you allocated a fixed-sized block, you could not perform an arbitrary number of allocations. The same holds for the stack. You can not dynamically create objects on the stack; your object’s lifetime is bound to the lifetime of the stack.
Variability
The variability is, of course, the benefit of dynamic memory allocation. This is true – with small restrictions – for the memory pool, if you have memory pools of various sizes or the memory pool is sufficiently big enough. Therefore, the program can react to the extraordinary memory request. This benefit will not hold for the stack or the allocation of the fixed-sized memory block. Both memory allocations require predictable memory requirements.
The big picture
In the end, the table provides an overview of all criteria.
A want to say a few words about the table. I sometimes choose the answer Yes/No in the case of the memory pool. The answer depends on the fact how many memory pools are available. I want to emphasize one point. The memory pool offers the best of two worlds. On the one hand, you have – like in the case of dynamic memory allocation – dynamic behavior; on the other hand, you have fully deterministic temporal behavior – like a stack of a fixed-sized memory block – for each memory allocation. The strength is reflected in the table.
What’s next?
Jonathan Müller, author of the English blog foonathan::blog() and the particular author of the memory library (“STL compatible C++ memory allocator library using a new RawAllocator concept that is similar to an Allocator but easier to use and write.”) will write in the next post about his memory pool allocators. I’m very happy to pronounce it. It would be quite challenging if I learned at least one lesson from these posts about memory allocation with C++.
{tooltip} {end-texte} Go to Leanpub/cpplibrary “What every professional C++ programmer should know about the C++ standard library”. {end-tooltip} Get your e-book. Support my blog.
Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Jozo Leko, John Breland, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Mario Luoni, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Daniel Hufschläger, Alessandro Pezzato, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Leo Goodstadt, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, Michael Young, Holger Detering, Bernd Mühlhaus, Stephen Kelley, Kyle Dean, Tusar Palauri, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, Stephen Totten, Wolfgang Fütterer, Matthias Grün, Phillip Diekmann, Ben Atakora, Ann Shatoff, Rob North, Bhavith C Achar, Marco Parri Empoli, Philipp Lenk, Charles-Jianye Chen, Keith Jeffery, Matt Godbolt, and Honey Sukesan.
Thanks, in particular, to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, John Nebel, Mipko, Alicja Kaminska, Slavko Radman, and David Poole.
My special thanks to Embarcadero | |
My special thanks to PVS-Studio | |
My special thanks to Tipi.build | |
My special thanks to Take Up Code | |
My special thanks to SHAVEDYAKS |
Modernes C++ GmbH
Modernes C++ Mentoring (English)
Rainer Grimm
Yalovastraße 20
72108 Rottenburg
Mail: schulung@ModernesCpp.de
Mentoring: www.ModernesCpp.org
Modernes C++ Mentoring,
Leave a Reply
Want to join the discussion?Feel free to contribute!