Enhance your dynamic memory allocation in C++ with an undocumented
MFC class (CFixedAlloc)
I never stop to be amazed by what you can find by browsing the MFC source code files. My latest discovery is rather spectacular. It consists of a small utility class that allows modifying how objects for a given class are dynamically allocated. This class is
CFixecAlloc. It is used inside the famous
CString class to allocate string buffers. Using
CFixedAlloc with the existing code requires very minimal changes and strives surprising improvements in performance. In this
C++ Windows programming tutorial, I will discuss CRT dynamic allocation overheads, usual alternatives to CRT shortcomings, the anatomy of the
CFixedAlloc class, how to use
CFixedAlloc in your programs, and finally, I will present a demo application so you can see by yourself what
CFixedAlloc can do for your programs.
It is a well known fact that dynamic memory allocation is expensive. It incurs performance overhead both in execution time and in space. If you need to be convinced, just take a peak in the malloc.c file provided with the CRT source code files.
malloc() function is a somehow complex function that takes some time to be executed. Concerning the space overhead, the subject is a bit complex. Here is an overview. Depending on the version of VC++ you are using when you compile your program, and the Windows version where your program is running, a different version of heap will be used. This is out of scope for this article but if you are curious about how CRT chooses the heap version, you can find the function
__heap_select() in the heapinit.c file. In the CRT winheap.h header file, three heap versions are defined:
V5 and V6 heap versions map to heap implementations private to the CRT library while the system heap maps directly to the Win32 heap services (
HeapAlloc(), etc ...). What is interesting about the V5 and V6 versions is that you can know exactly what is the space overhead for these heaps by looking at the CRT source code. For example, you can find this statement for the V6 heap:
// add 8 bytes entry overhead and round up to next para size
sizeEntry = (intSize + 2 * (int)sizeof(int) +
(BYTES_PER_PARA - 1)) & ~(BYTES_PER_PARA - 1);
BYTES_PER_PARA equals 16 bytes. This is a huge overhead. Consider the case where you would request twelve bytes. The CRT would reserve 32 bytes for this request. This is more than the double of what you requested! Unfortunately (or fortunately, it depends on your perspective), the V5 and the V6 heap are nowadays rarely used and we cannot know for sure what is the
HeapAlloc() overhead because we do not have access to this source code. However, it is a very good assumption that there is an overhead. Microsoft states this fact in the
The system uses memory from the private heap to store heap support structures, so not all of the specified heap size is available to the process. For example, if the
HeapAlloc function requests 64 kilobytes (K) from a heap with a maximum size of 64K, the request may fail because of system overhead.
Some people have written memory pool classes to workaround the CRT heap overhead. The excellent article from Uri Twig is an example of such a class. However, most of them require massive code change to replace all
operators invocations to some calls to the buffer pool class member functions. Another common potential limitation (potential because it depends on your needs) is that they lack thread safety.
CFixedAlloc addresses these limitations and it will be explained how in the next section.