Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Recycle

0.00/5 (No votes)
3 Oct 2001 1  
The Recycle program has been designed to automate the release of system memory.

1. Introduction:

The most common yet repeated mistake that programmers make is while using system memory. Two most obvious situations are:

  1. When memory is allocated but not released, when not needed - This commonly occurs when some function allocates memory and calls other functions that allocate memory too. In such successive function calls, if one of the functions, down the sequence returns failure, all previously allocated memories need to be explicitly released. This requires the programmer to write code for releasing memory which is often forgotten,
  2. When memory is allocated for sending across task or process boundaries but isn�t returned to the system - A contiguous chunk of memory is needed when data is to be sent (as message) to another task or process. This mechanism is such that, the data in this contiguous chunk is first copied by the operating system in its own buffers and then passed to the destination task or process. Thus as soon as the message is sent, the memory that was allocated for it�s data needs to be released. 

If allocated memory is not returned to the system, soon the system will run out of its memory resource and all subsequent allocation requests will fail. This may not be such critical a problem in normal non-real time environments. But in real time systems like telecommunication switches, routers, aircraft systems etc, such runaway memory can wreck havoc.

The Recycle program has been designed to automate the release of system memory, allocated in the above listed situations. The programmer is saved of the job of writing any code for releasing unwanted memory. But all this comes at the cost of a little system overhead. The details will be explained as I describe the exact functionality of the Recycle program.

I designed the program for a real time environment that I work in. Real time systems still predominantly use C and that�s the reason why the code is in C and not C++. There is no MFC at use but the code can be plugged into almost any system with little or no customization. 

Recycle consists of 2 files, recycle.h and recycle.c and a test file testmain.c. The files contain comments at appropriate places. 

2. Operational Description:

Recycle automates the release of unwanted memory, eliminating the need of writing special code for explicitly freeing it. Recycle uses a stack that stores the information necessary to keep track of the memory to be released.

The memory allocation function provided by the operating system has been encapsulated by the function Allocate(). Any application that needs to use the services of Recycle will use the macro DECL_STACK_HANDLE, globally and thus declare a global object of the stack handle. The application must also initialize this object by using the macro MEMSET_STACK_HANDLE, in its entry point or a (similar) suitable function. Once the handle is initialized, Recycle is ready for use.

A function needing system memory will first use the macro SET_FN_SCOPE. This macro declares a void* variable and assignees the �pointer to this function�, to it. 

Eg:

void Trial1()
{
SET_FN_SCOPE(Trial1);
//

The user can now use the function Allocate(). Before calling Allocate(), the user must have a look at the macro ALLOC_MEM(). This may need to be modified depending on the type of memory allocation system call that the target operating system provides. The user will simply replace the �malloc� with any other similar function (identical prototype) that the OS provides. 

A call to Allocate() will construct the stack and store the function scope, the pointer to allocated memory, the size of the memory and the purpose for which the memory was allocated. The stack will grow each time Allocate() is called. This is done internally by the function PUSH() that pushes these parameters on the stack.

The scope of a function is stored as a function pointer to that function. Its required to keep a track of all the memory that is allocated by a function and later freeing it if needed. Memory allocated by a function will be freed only by that function. A stack was used for this job as this mechanism is analogous to that used by the operating system. 

The stack will unwind in the cases described in the first section. The RETURN() macro, called by each function will in turn call the function POP() for popping the stack. POP first checks the function scope of the existing function with that stored in the stack, starting from the top. If the scope matches, it checks the allocation status (MALLOC_SUCCESS, OUT_OF_SCOPE). If its MALLOC_SUCCESS, it means that memory is persistent and doesn�t need to be freed. Thus only the stack node is popped and memory is left intact. POP() will loop over all the stack nodes that have the same function scope. This ensures that the entire function scope is covered and treated appropriately. In case a MALLOC_FAIL is returned, the stack will free the memory as well as the stack node, for the complete function scope. Similar will be the operation for OUT_OF_SCOPE

Freed memory is also set to zero, by POP(). Note here that MALLOC_FAIL is used to represent all other conditions but SUCCESS and OUT_OF_SCOPE

3. Guidelines for Use:

  1. All functions that need to allocate memory must have enumerated return values. The enum indicating success should have the same value as MALLOC_SUCCESS. This is demonstrated in file testmain.c,
  2. Users should appropriately use all the macros as instructed earlier and in file testmain.c. Before using the stack, a user should be aware of the type of the application � single threaded or multi threaded. A multithreaded application will require some form of mutual exclusion mechanism. No such mechanism has been described here as the calls differ from OS to OS.

4. Overhead on the system:

Using the stack, and if needed, the mutual exclusion methods, induces an overhead on the system. Its up to the user to exactly evaluate this overhead. In a normal single threaded system, the size of the stack doesn�t normally go above 4-5 nodes at a time, unless a long link-list is being constructed in a single function. And the lifetime of the stack too is only as much as that of the function call. So this code doesn�t have any significant affect on such systems. The performance could be an issue in very time critical real time systems. Typical problem could be like when tasks context switch if having to wait for the stack semaphore to be released, or when the system has to work in very limited memory and the stack could be a memory overhead. But most systems would work fine with this program. 

This code has not been extensively tested with real time system. A user is advised to test this code in the target environment thoroughly, before finally integrating it with the application. This program is in for use in our future projects. 

testmain.c

This file demonstrates the use of the Recycle interfaces. The file is self-explanatory and is complete with comments wherever necessary. A user can enable or disable printf statements by defining or un-defining the ENABLE_PRINT directive. It�s enabled by default. To test the count of allocation and de-allocation of memory a counter could be used. The counter will increment each time memory is allocated and decrement when memory is released.

Any comments, questions or corrections in this code are of great value to me and are most welcome.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here