Memory management in C is defined as “explicit” because both the operations to reserve and liberate memory need to be explicitly included in the code. In other programming languages, such as for example Java, the execution environment is in charge of recovering those memory portions that are no longer used. Derived from the explicit memory management there are several anomalies that may appear when memory fragments cannot be liberated because there is no possibility to access them. This is what is known as a “memory leak”. This memory portion remains reserved but not accessible until the end of the program execution.
When a program starts to execute, its memory is divided into three portions: the stack, the global memory and the “heap”. The heap is used to reserve and liberate memory portions during the program execution. But, how is this memory actually managed?
The operating system maintains an internal table with all
    the memory portion in the heap that are occupied and the pointers returned
    as a result of a memory request. When a program executes the
    malloc function to request a new fragment, the system search
    for a portion of the requested size, if it exists, returns its initial
    address and annotates that block as occupied. Analogously, when a program
    calls the function free to liberate a fragment, the system
    searches the table for that fragment (which must be annotated as reserved)
    and frees the space for future use. The following figure shows this data
    structure and the operations.

At the request of a memory block of 2048 bytes, the memory
    manager answers with the address of a block that has previously marked as
    occupied. The call to free is analogous, but instead of a size,
    it receives a memory address of a previously reserved block, search that
    address in the table, and if exists, it is marked as available.
This memory management scheme forces the programs to follow
    very precise guidelines to guarantee a correct use of memory and obtain the
    best performance in a program. For example, if a program uses a large
    quantity of dynamic data (that is, those stored in memory requested to the
    manager through malloc) and does not free these data as soon as
    possible, it may run out of memory and be unable to finish its
    execution.