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.
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
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);
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:
- 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.
- 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.
- 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.
- 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
- http://www.design-reuse.com/articles/25090/dynamic-memory-allocation-fragmentation-c.html
No comments:
Post a Comment