[an error occurred while processing this directive]
CHAPTER 13 MEMORY MANAGEMENT TECHNIQUES USING CLASSES
How do I...
- 13.1 Make a simple class to clean up dynamically allocated memory automatically?
- 13.2 Make a class that automatically cleans up objects allocated with new?
- 13.3 Make an object that deallocates itself when there is no more code referencing it?
Managing memory is something few programmers think about when designing a program, but wish they had when staring at debugger output. Although performance tuning of a program will often deal with memory management issues, memory management is more than just counting the bytes allocated and deallocated in a program.
Shuffling bytes around in main memory is one of the slowest operations on a computer, and although its faster than accessing the hard disk or the video memory, things would go much faster if the only thing the processor had to fetch from main memory was code. Your operating system does a lot of shuffling of data in memory in its management of caches and other data areas, as well as handling things like virtual memory (which allows your computer to use free disk space as an extension to system RAM). This is a relatively fixed cost, but as a programmer you have control over how your program uses memory (how much, how often things are copied, and so on).
Another technique no programmer should be without is a basic understanding of how memory managers are implemented and their limitations. Easy-to-implement techniques are also covered because for most programs these produce excellent results with minimal effort.
13.1 Make a Simple Class to Clean Up Dynamically Allocated Memory Automatically
This How-To uses scope to automatically deallocate dynamically allocated memory. It is most useful in situations in which the new and delete operators arent the most efficient. This allows experimentation with other allocation schemes, such as operating system API calls, to be done invisibly to the rest of the program.
13.2 Make a Class That Automatically Cleans Up Objects Allocated with new
This How-To uses a template for type-safe memory management to provide functionality similar to that of How-To 13.1, it underlines a different approach.
13.3 Make an Object That Deallocates Itself When There Is No More Code Referencing It
Counting the number of references to an object is useful in multithreaded programming environments because objects might not have finished being processed by other threads when the thread that allocated the object expires.
13.1 Make a simple class to clean up dynamically allocated memory automatically?
Problem
You might want to do this for a number of reasons. The primary reason is so the user of the class does not need to remember to match up new calls with deletes because the scope mechanism and the class destructor will handle it automatically. This is not the only reason, though.
Some systems (Windows 3.1, most notably) do not lend themselves well to the use of new and delete operators (which, for the most part, eventually call malloc() or free()). Often this problem comes from the memory manager or the systems segmentation model. Under the 16-bit Windows operating systems, most data allocated using new and malloc() comes from the applications local heap, which is only 64KB in size. Although more memory can be had using global memory allocation functions, managing it is quite a hassle.
Operating system direct memory allocation functions are often quite complicated, with lots of arguments and so on. The use of these functions also makes porting the code difficult. Another reason might be that the operating system provides a more robust heap manager (OS/2 provides an extremely fast memory suballocation manager, for instance).
Encapsulating the process in a memory manager helps the process in a number of ways:
- It keeps the actual function calls to the operating systems memory allocation routines in one place. This makes porting the code easier because the memory allocations in the program need not change as long as the memory allocation objects interface remains the same.
- Its possible to experiment with different memory allocation techniques (which are not necessarily operating systemspecific) without affecting the code that uses the memory management class.
- It is easy to keep statistics on the memory the program used.
- The memory-managing object can perform all the error checking, and even handle the problems in a way best suited to the operating system without the users (that is, the other programmers) of the object knowing how its done.
- A memory object can perform advanced functions such as reference counting, providing a copy-on-write scheme, and also calling operating systemoptimized resizing functions to increase program performance and reliability.
- The memory object can automatically deallocate the memory after the object falls out of scope. This can reduce the occurrence of memory leaks tremendously. Just think of what could happen to an application if a delete call were missed in a function called one million times!
These techniques require some discipline to implement. It is sometimes difficult to unlearn the use of new and delete for one project, but these techniques can go a long way toward reducing the amount of debugging time for a project.
Steps
It is best to start out with code that is generic enough to be used everywhere in the program. After that, its possible to use this code in overloaded new and delete operators, for example. In this example, the code will be modularized as well as object-oriented. It essentially entails keeping the code specific to memory management in one C++ file, which is compiled with the other code. Programmers get the definitions for the classes through a header file. Because this code is quite generic, placing it in a module makes it easier to reuse elsewhere.
This example will use only the new and delete functions because they are available in every C++ system to allow memory to be allocated dynamically that automatically deallocates itself when the object managing it falls out of scope. In this case, it will also be possible to implement operators to work on the memory if this functionality is desired, or, for instance, to set the memory contents to 0 before making it available for use.
There are as many approaches to this problem as there are C++ programmers. The example detailed here will allocate generic memory.
This code is best put into a header file to make it more reusable.
|