Dynamic Memory Allocation: Basic Concepts

References

Dynamic Memory Allocation

Dynamic Memory Allocation

The malloc Package

malloc Example

#include <stdio.h>
#include <stdlib.h>

void foo(long n) {
    long i, *p;

    /* Allocate a block of n longs */
    p = (long *) malloc(n * sizeof(long));
    if (p == NULL) {
        perror("malloc");
        exit(0);
    }

    /* Initialize allocated block */
    for (i=0; i<n; i++)
        p[i] = i;
    /* Do something with p */
    ...

    /* Return allocated block to the heap */
    free(p);
}

Sample Implementation

Constraints

Performance Goal: Throughput

Performance Goal: Minimize Overhead

malloc Heap Visualization Example

Fragmentation

Implementation Issues

Knowing How Much to Free

Keeping Track of Free Blocks

Method 1: Implicit Free List

Detailed Implicit Free List Example

Implicit List: Data Structures

Implicit List: Header access

Implicit List: Traversing the List

Implicit List: Finding a Free Block

static block_t *find_fit(size_t asize) {
    block_t *block;
    for (block = heap_start; block != heap_end;
         block = find_next(block))
    {
        if (!(get_alloc(block)) && (asize <= get_size(block)))
            return block;
    }
    return NULL; // No fit found
}

Implicit List: Finding a Free Block

Implicit List: Allocating in Free Block

Implicit List: Splitting Free Block

// Warning: This code is incomplete

static void split_block(block_t *block, size_t asize) {
    size_t block_size = get_size(block);

    if ((block_size - asize) >= min_block_size) {
        write_header(block, asize, true);
        block_t *block_next = find_next(block);
        write_header(block_next, block_size - asize, false);
    }
}

Implicit List: Freeing a Block

Implicit List: Coalescing

Implicit List: Bidirectional Coalescing

Implementation with Footers

Splitting Free Block: Full Version

static void split_block(block_t *block, size_t asize) {
    size_t block_size = get_size(block);

    if ((block_size - asize) >= min_block_size) {
        write_header(block, asize, true);
        write_footer(block, asize, true);
        block_t *block_next = find_next(block);
        write_header(block_next, block_size - asize, false);
        write_footer(block_next, block_size - asize, false);
    }
}

Constant Time Coalescing (Case 1)

Constant Time Coalescing (Case 2)

Constant Time Coalescing (Case 3)

Constant Time Coalescing (Case 4)

Heap Structure

Top-Level Malloc Code

const size_t dsize = 2*sizeof(word_t);

void *mm_malloc(size_t size)
{
    size_t asize = round_up(size + dsize, dsize);

    block_t *block = find_fit(asize);

    if (block == NULL)
        return NULL;

    size_t block_size = get_size(block);
    write_header(block, block_size, true);
    write_footer(block, block_size, true);

    split_block(block, asize);

    return header_to_payload(block);
}

Top-Level Free Code

void mm_free(void *bp)
{
    block_t *block = payload_to_header(bp);
    size_t size = get_size(block);

    write_header(block, size, false);
    write_footer(block, size, false);

    coalesce_block(block);
}

Disadvantages of Boundary Tags

No Boundary Tag for Allocated Blocks

Summary of Key Allocator Policies

Implicit Lists: Summary