Saturday 10 January 2015

DYNAMIC MEMORY ALLOCATION


DYNAMIC MEMORY ALLOCATION
Dynamic memory allocation is used in assembly language and high level languages for building data structures. In object oriented languages it is used to get the memory used to construct objects.
This memory comes from the heap area of memory segment in process.
 C provides features for allocating and deallocating the memory from heap area which is knowns as dynamic allocation and deallocation.
 The following memory management prototypes are:
  • calloc() which dynamically allocates memory - “c” stands for contiguous allocation. calloc is typically used to allocate contiguous space for arrays. The memory is with all bits set to zero/ char arrays to NULL.
  • malloc() which dynamically allocates memory - “m” stands for memory. Similar to calloc but more general purpose allocation function. Does not initialize memory (user has to do that if necessary).
  • realloc() which dynamically reallocates allocates memory - “r” stands for reallocate memory. This function allows the programmer to change the size of previously allocated memory to a new size.
  • free() which deallocates memory releasing the block of memory back to the heap. If memory is continuously allocated and not released two things may happen: memory leak or the requesting process could be killed. Take care to free memory.
The memory management functions use “pointer to void” (void *) which allows the programmer to assign the returned pointer to memory to any struct, array, variable without casting.
Malloc, Sizeof, and Free
The malloc Function is used to allocate a block of memory on run time.
  
The syntax of malloc() function is given below:
  ptr=(cast-type*)malloc(byte-size)  
 ptr=void *malloc(byte-size)
That is to say it returns a pointer of type void * that is the start in memory of the reserved portion of size      number_of_bytes.
If memory cannot be allocated a
NULL pointer is returned.
It doesn't initialize memory at execution time, so it has garbage value initially.

Since a void * is returned the C standard states that this pointer can be converted to any type. The size_t argument type is defined in stdlib.h and is an unsigned type.
So:

    char *cp;
                cp = malloc(50);

attempts to get 50 bytes and assigns the start address to cp.
Also it is usual to use the sizeof() function to specify the number of bytes:

    int *ip;
                ip = (int *) malloc(100*sizeof(int));

Some C compilers may require to cast the type of conversion. The (int *) means coercion to an integer pointer. Coercion to the correct pointer type is very important to ensure pointer arithmetic is performed correctly. I personally use it as a means of ensuring that I am totally correct in my coding and use cast all the time.
It is good practice to use sizeof() even if you know the actual size you want -- it makes for device independent (portable) code.
sizeof can be used to find the size of any data type, variable or structure. Simply supply one of these as an argument to the function.
SO:

   int i;
                struct Node 
                  {
                    float x,y,z
                  };
                typedef struct Node sn;

                sizeof(int), sizeof(i),
                sizeof(struct Node) and
                sizeof(sn) are all ACCEPTABLE

In the above we can use the link between pointers and arrays to treat the reserved memory like an array. i.e we can do things like:
   ip[0] = 100;
or
   for(i=0;i<100;++i) scanf("%d",ip++); 
Deallocation
When the memory is no longer needed, it should be returned to the memory heap.

When you have finished using a portion of memory you should always free() it. This allows the memory freed to be available again, possibly for further malloc() calls
The memory occupied by malloc() or calloc() functions must be released by calling free() function. Otherwise, it will consume memory until program exit.
 Syntax of free() function. 
     free(ptr) 
The function free() takes a pointer as an argument and frees the memory to which the pointer refers.
NOTE:-ALWAYS RESET THE POINTER VARIABLE TO NULL AFTER RETURNING MEMORY . 
Calloc and Realloc
There are two additional memory allocation functions, Calloc() and Realloc().
The syntax of calloc() function is given below:
ptr=(cast-type*)calloc(number, byte-size) 

Their prototypes is given below:
void *calloc(size_t num_elements, size_t element_size};

Syntax of realloc() function. 
    ptr=realloc(ptr, new-size)  
Their prototypes is given below:
 void *realloc( void *ptr, size_t new_size);

Malloc does not initialise memory (to zero) in any way. If you wish to initialise memory then use calloc. Calloc there is slightly more computationally expensive but, occasionally, more convenient than malloc. Also note the different syntax between calloc and malloc in that calloc takes the number of desired elements, num_elements, and element_size, element_size, as two individual arguments.
Thus to assign 100 integer elements that are all initially zero you would do:

    int *ip;
                ip = (int *) calloc(100, sizeof(int));
Realloc is a function which attempts to change the size of a previous allocated block of memory. The new size can be larger or smaller. 
 If the block is made larger then the old contents remain unchanged and memory is added to the end of the block. If the size is made smaller then the remaining contents are unchanged.
  If the original block size cannot be resized then realloc will attempt to assign a new block of memory and will copy the old block contents.
 Note a new pointer (of different value) will consequently be returned. You must use this new value. If new memory cannot be reallocated then realloc returns NULL.
Thus to change the size of memory allocated to the *ip pointer above to an array block of 50 integers instead of 100, simply do:
   ip = (int *) calloc( ip, 50);
Advantages of Dynamic Memory Allocation
      The main advantage of using dynamic memory allocation is preventing the wastage of memory. This is because when we use static memory allocation, a lot of memory is wasted because all the memory allocated cannot be utilised. Thus dynamic memory allocation helps us to allocate memory as and when required and thus saves memory.
  • In static memory allocation, if we allocate 1000 memory locations as int name[1000]; While running the program only half of this may be used. The rest is unused and idle. It is a wastage of memory.
  • If we want to change the size of the array in the program, it is possible by reediting the program. It is a time consuming process. 
In dynamic memory allocation the above two problems won't occur because, the memory space for variables is allocated only during execution.
Disadvantages of Dynamic Memory Allocation
  •  Dynamic memory allocation is slower than static memory allocation. This is because dynamic           memory allocation happens in the heap area.
  • Dynamic memory needs to be carefully deleted after use. They are created in non-contiguous area of memory segment.
  • Dynamic memory allocation causes contention between threads, so it degrades performance when it   happens in a thread.
  • Memory fragmentation.

Memory Fragmentation
The best way to understand memory fragmentation is to look at an example. For this example, it is assumed hat there is a 10K heap. First, an area of 3K is requested, thus:
         #define K (1024)
         char *p1;
         p1 = malloc(3*K);
Then, a further 4K is requested:
        p2 = malloc(4*K);
3K of memory is now free.
Some time later, the first memory allocation, pointed to by p1, is de-allocated:
        free(p1);
This leaves 6K of memory free in two 3K chunks. A further request for a 4K allocation is issued:
       p1 = malloc(4*K);
This results in a failure – NULL is returned into p1 – because, even though 6K of memory is available, there is not a 4K contiguous block available. This is memory fragmentation.
Common Mistakes with Dynamic Memory Allocation
There are a number of errors that occur commonly when using dynamic memory:
  1. Dangling Pointers:
    • If dynamic memory is freed up using free, but the pointer variable is not reset back to NULL, then the pointer still contains the address of where the dynamic memory used to be. Using ( following ) this pointer later can have a wide variety of consequences, depending on what if anything is done with that block of memory in the meantime.
    • The problem can be especially difficult to find if multiple pointers point to the same place. Even though one of the pointers may have been reset to NULL, the other pointers could be left dangling.
  2. Memory Leaks:
    • If dynamic memory is continuously allocated without ever being freed back up again, the system will eventually run out of memory, which will result in either a stack overflow error or a failure of the dynamic memory allocation calls.
    • This type of error occurs most commonly when dynamic memory is allocated in a loop.
    • Always make sure to free up dynamic memory when it is no longer being used.
    • Always check the return value of malloc, calloc, or realloc to verify that it did not return NULL.
    • Memory leaks can be extremely hard to find, because they often don't result in program failures until the program runs for a sufficiently long time, so unless the program tests run long enough, the problems won't be detected.
  3. Double deallocation
    • If an attempt is made to deallocate memory pointed to by a dangling pointer, it can cause all sorts of problems, particularly if that memory has since been reallocated for other purposes.
  4. Use of uninitialized pointers
    • As covered earlier, any variable that is not initialized starts out with a random unknown value, which will generally be different from one run of the program to another. If the variable in question is a pointer, then the problem can be especially difficult when the uninitialized pointer is used later on in the program.
      • In a best case, the pointer will point to inaccessable memory, and a "segmentation fault" will occur, stopping the program.
      • If the bad pointer points to a valid location within your data or worse your code, then any number of problems can occur, possibly at some later time in the program.
References
  1. http://www.design-reuse.com/articles/25090/dynamic-memory-allocation-fragmentation-c.html