Skip to content

Islam-Imad/Heap-Memory-Allocator

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Heap Memory Allocator

A thread-safe custom heap memory allocator implemented in C, featuring an AVL tree-based free block management system, automatic memory coalescing, and support for both small (brk) and large (mmap) allocations.

Table of Contents

Features

🚀 High Performance

  • AVL Tree-based free block management for O(log n) allocation/deallocation
  • Efficient memory coalescing to reduce fragmentation
  • Block splitting to minimize wasted space
  • Optimized for both small and large allocations

🛡️ Memory Safety

  • Comprehensive boundary checking with headers and footers
  • Double-free protection and corruption detection
  • Memory pattern verification in debug mode
  • Automatic heap trimming to release unused memory

🔄 Advanced Features

  • Thread-safe operations with mutex protection
  • Dual allocation strategies: brk() for small allocations, mmap() for large ones
  • Automatic fragmentation handling through intelligent coalescing
  • Configurable thresholds for allocation strategies

🧪 Robust Testing

  • Comprehensive test suite with unit and integration tests
  • Custom testing framework with colorized output
  • Stress testing for fragmentation and performance
  • Memory integrity verification utilities

Architecture

Memory Layout

The allocator uses a sophisticated block structure with headers and footers for efficient management:

[Block Header][User Data][Footer]

Each block contains:

  • Header: Size, state (FREE/ALLOCATED/MMAP_ALLOCATED), AVL tree pointers, height
  • User Data: The actual allocated memory returned to the user
  • Footer: Size information for backward traversal

Free Block Management

Free blocks are organized in an AVL tree (self-balancing binary search tree) sorted by size:

  • Primary key: Block size (for efficient best-fit allocation)
  • Secondary key: Block address (for deterministic ordering of same-size blocks)
  • Balanced operations: O(log n) insertion, deletion, and lookup

Allocation Strategies

  1. Small Allocations (< 128KB): Use brk() system call

    • Extends the heap boundary
    • Efficient for frequent small allocations
    • Supports coalescing and splitting
  2. Large Allocations (≥ 128KB): Use mmap() system call

    • Direct memory mapping from OS
    • Avoids heap fragmentation
    • Immediate return to OS on free

Getting Started

Prerequisites

  • GCC or compatible C compiler
  • CMake 3.10 or higher
  • Linux operating system (uses Linux-specific system calls)
  • pthreads library

Building the Project

# Clone the repository
git clone <repository-url>
cd Heap-Memory-Allocator

# Create build directory
mkdir build
cd build

# Configure with CMake
cmake ..

# Build the project
make

# Build specific targets
make alloc          # Main demo executable
make run_tests      # Build and run all tests

Running the Demo

# Run the main demonstration
./alloc

The demo will:

  1. Initialize the allocator
  2. Allocate arrays of different sizes
  3. Write data to verify memory integrity
  4. Display allocated data
  5. Free all memory and show the final free block tree

API Reference

Core Functions

init_HeapMemoryAllocator(struct HeapMemoryAllocator *allocator)

Initializes a new heap memory allocator instance.

  • Parameters: allocator - Pointer to allocator structure
  • Thread Safety: Not thread-safe (call before concurrent usage)

void *my_malloc(struct HeapMemoryAllocator *allocator, size_t size)

Allocates memory of the specified size.

  • Parameters:
    • allocator - Pointer to allocator instance
    • size - Number of bytes to allocate
  • Returns: Pointer to allocated memory or NULL on failure
  • Thread Safety: Thread-safe

void my_free(struct HeapMemoryAllocator *allocator, void *ptr)

Frees previously allocated memory.

  • Parameters:
    • allocator - Pointer to allocator instance
    • ptr - Pointer to memory to free
  • Thread Safety: Thread-safe

destroy_HeapMemoryAllocator(struct HeapMemoryAllocator *allocator)

Cleans up allocator resources.

  • Parameters: allocator - Pointer to allocator structure
  • Thread Safety: Not thread-safe (call after all usage is complete)

Data Structures

struct HeapMemoryAllocator

Main allocator structure containing:

  • void *heap_start - Start of the heap region
  • block_tree_t free_blocks - AVL tree of free blocks
  • pthread_mutex_t lock - Mutex for thread safety

block_t

Individual memory block structure:

  • size_t size - Size of user data
  • block_state state - Block state (FREE/ALLOCATED/MMAP_ALLOCATED)
  • int height - AVL tree height
  • struct block *left, *right - AVL tree pointers

Testing

Running Tests

# Run all tests with verbose output
ctest --verbose

# Run specific test categories
./test_basic_malloc
./test_coalescing
./test_integration

# Run tests with memory checking (if Valgrind is installed)
valgrind --leak-check=full ./test_basic_malloc

Test Coverage

The test suite includes:

Unit Tests

  • Basic allocation/deallocation functionality
  • Edge cases: zero-size allocation, very large allocations
  • Memory alignment verification
  • Error handling for invalid parameters

Integration Tests

  • Stress testing with multiple allocation patterns
  • Fragmentation scenarios and coalescing verification
  • Mixed size allocations and memory integrity
  • Concurrent access patterns (thread safety)

Performance Tests

  • Allocation/deallocation speed benchmarks
  • Memory overhead measurements
  • Fragmentation impact analysis

Writing New Tests

See the comprehensive Testing Guide for detailed instructions on:

  • Test file structure and organization
  • Available testing macros and utilities
  • Best practices for memory testing
  • Debugging techniques

Performance Characteristics

Time Complexity

  • Allocation: O(log n) average case, O(n) worst case for heap growth
  • Deallocation: O(log n) for tree operations
  • Coalescing: O(log n) for each adjacent block check

Space Complexity

  • Overhead: 24 bytes per block (header + footer)
  • Tree overhead: O(n) for free block tree
  • Alignment: 8-byte aligned allocations

Benchmarks

Typical performance on modern hardware:

  • Small allocations (64B): ~100ns per malloc/free pair
  • Medium allocations (1KB): ~200ns per malloc/free pair
  • Large allocations (>128KB): ~1µs per malloc/free pair (mmap overhead)

Memory Management Details

Block Structure

Header (20 bytes):     Footer (8 bytes):
┌─────────────────┐    ┌─────────────────┐
│ size_t size     │    │ size_t size     │
│ block_state     │    └─────────────────┘
│ int height      │
│ block_t* left   │
│ block_t* right  │
└─────────────────┘

Coalescing Algorithm

When a block is freed:

  1. Check next block: If adjacent and free, merge
  2. Check previous block: If adjacent and free, merge
  3. Update tree: Remove old blocks, insert coalesced block
  4. Update footer: Ensure size consistency

Splitting Algorithm

When allocating from a larger free block:

  1. Check profitability: Ensure remainder is large enough for minimum block size
  2. Calculate split point: Header + requested size + footer
  3. Create new block: Initialize remainder as free block
  4. Update tree: Insert new free block

Thread Safety

The allocator is designed for concurrent use:

Synchronization Strategy

  • Global lock: Protects allocator state during allocation/deallocation
  • Tree locks: Fine-grained locking for AVL tree operations
  • Atomic operations: Where possible, for performance

Usage Guidelines

// Safe: Multiple threads can use the same allocator
struct HeapMemoryAllocator allocator;
init_HeapMemoryAllocator(&allocator);

// Thread 1
void *ptr1 = my_malloc(&allocator, 100);

// Thread 2 (concurrent)
void *ptr2 = my_malloc(&allocator, 200);

// Both threads can safely free
my_free(&allocator, ptr1);
my_free(&allocator, ptr2);

Configuration

Key configuration constants in include/my_malloc.h:

Allocation Thresholds

#define MMAP_THRESHOLD (128 * 1024)    // 128KB - Use mmap for larger allocations
#define BRK_TRIM_THRESHOLD (64 * 1024) // 64KB - Trim heap when top block exceeds this
#define MIN_BLOCK_SIZE (48)            // Minimum block size for splitting

Debugging Options

// Compile with -DDEBUG for additional checks
#ifdef DEBUG
    #define DEBUG_PRINT(...) printf(__VA_ARGS__)
#else
    #define DEBUG_PRINT(...)
#endif

Examples

Basic Usage

#include "my_malloc.h"

int main() {
    struct HeapMemoryAllocator allocator;
    init_HeapMemoryAllocator(&allocator);

    // Allocate memory
    int *array = (int*)my_malloc(&allocator, 10 * sizeof(int));
    if (array) {
        // Use the memory
        for (int i = 0; i < 10; i++) {
            array[i] = i * i;
        }

        // Free when done
        my_free(&allocator, array);
    }

    destroy_HeapMemoryAllocator(&allocator);
    return 0;
}

Advanced Usage with Error Handling

#include <string.h>
#include <assert.h>
#include "my_malloc.h"

void robust_allocation_example() {
    struct HeapMemoryAllocator allocator;
    init_HeapMemoryAllocator(&allocator);

    // Allocate with error checking
    void *ptr = my_malloc(&allocator, 1024);
    if (!ptr) {
        fprintf(stderr, "Allocation failed\n");
        return;
    }

    // Write pattern to verify memory
    memset(ptr, 0xAB, 1024);

    // Verify the memory is intact
    unsigned char *bytes = (unsigned char*)ptr;
    for (int i = 0; i < 1024; i++) {
        assert(bytes[i] == 0xAB);
    }

    my_free(&allocator, ptr);
    destroy_HeapMemoryAllocator(&allocator);
}

Troubleshooting

Common Issues

Segmentation Fault

  • Cause: Double free, use after free, or corruption
  • Solution: Use debugging tools like Valgrind, check for proper free pairing

Memory Leaks

  • Cause: Missing my_free() calls
  • Solution: Ensure every my_malloc() has corresponding my_free()

Poor Performance

  • Cause: Excessive fragmentation or inappropriate allocation sizes
  • Solution: Adjust allocation patterns, consider memory pooling

Build Errors

  • Cause: Missing dependencies or incompatible compiler
  • Solution: Ensure GCC and CMake are properly installed

Debug Mode

Compile with debugging information:

cmake -DCMAKE_BUILD_TYPE=Debug ..
make

Memory Debugging

# Run with Valgrind for detailed memory analysis
valgrind --leak-check=full --show-leak-kinds=all ./alloc

# Use AddressSanitizer for faster debugging
gcc -fsanitize=address -g main.c src/my_malloc.c -o alloc_debug

Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Add tests for new functionality
  4. Ensure all tests pass (make run_tests)
  5. Commit changes (git commit -m 'Add amazing feature')
  6. Push to branch (git push origin feature/amazing-feature)
  7. Open a Pull Request

Development Guidelines

  • Follow existing code style and naming conventions
  • Add comprehensive tests for new features
  • Update documentation for API changes
  • Ensure thread safety for new operations

License

This project is licensed under the MIT License.

About

My Heap Memory Allocator

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors