PracHub
QuestionsPremiumCoachesLearningGuidesInterview Prep

Quick Overview

This question evaluates a candidate's understanding of dynamic memory management, low-level resource handling, and algorithmic data structures (e.g., segregated free lists, interval/balanced trees, buddy system) with attention to alignment, internal/external fragmentation, and block coalescing.

  • Medium
  • OpenAI
  • Coding & Algorithms
  • Software Engineer

Implement a Simulated Memory Allocator

Company: OpenAI

Role: Software Engineer

Category: Coding & Algorithms

Difficulty: Medium

Interview Round: Technical Screen

Implement a simulated memory allocator that supports allocate(size) and free(ptr) operations analogous to malloc and free. Treat memory as a contiguous byte array of capacity N provided at initialization and return identifiers for allocated blocks. Achieve low-latency operations under heavy workloads; justify your choice of data structures (e.g., segregated free lists, interval/balanced trees, buddy system). Handle alignment and external/internal fragmentation, and support coalescing of adjacent free blocks. Provide time and space complexity analysis, discuss trade-offs among first-fit/best-fit/next-fit strategies, and describe tests and benchmarks you would write to validate correctness and performance.

Quick Answer: This question evaluates a candidate's understanding of dynamic memory management, low-level resource handling, and algorithmic data structures (e.g., segregated free lists, interval/balanced trees, buddy system) with attention to alignment, internal/external fragmentation, and block coalescing.

Implement a simulated memory allocator over a contiguous byte array [0, capacity). For deterministic judging, use a buddy allocator. Allocation rules: - capacity and alignment are powers of two. - alloc(size): if size <= 0, return -1. - Round the request up to max(alignment, next power of two greater than or equal to size). - Use the smallest free buddy block that can satisfy the request. - If a larger block is chosen, repeatedly split it into two equal halves. Always continue with the left half and put the right half back into the free structure. - Return the starting offset of the allocated block, or -1 if no block fits. Free rules: - free(ptr): if ptr is not the exact start of a currently allocated block, return 0. - Otherwise free it, repeatedly coalescing with its free buddy of the same size, and return 1. Process all operations in order and return the result of every operation. This models a low-latency allocator: buddy allocation gives predictable split/coalesce behavior and reduces external fragmentation, but it can waste memory internally because requests are rounded up. In an interview, you should also be able to compare this with first-fit, best-fit, and next-fit interval allocators, and discuss tests such as double-free, full-capacity allocation, alignment checks, long random workloads, and coalescing chains.

Constraints

  • 1 <= alignment <= capacity <= 2^20
  • capacity and alignment are powers of two
  • 1 <= len(operations) <= 2 * 10^5
  • Each operation is either ('alloc', size) with 0 <= size <= capacity, or ('free', ptr) with 0 <= ptr < capacity

Examples

Input: (16, 4, [('alloc', 3), ('alloc', 5), ('free', 0), ('alloc', 4), ('free', 8), ('free', 0), ('alloc', 12)])

Expected Output: [0, 8, 1, 0, 1, 1, 0]

Explanation: 3 bytes rounds to 4 and gets pointer 0. 5 bytes rounds to 8 and gets pointer 8. After freeing 0 and later freeing 8 and 0 again, all memory coalesces back into one 16-byte block, so the final 12-byte request rounds to 16 and is allocated at 0.

Input: (8, 8, [('alloc', 1), ('alloc', 1), ('free', 4), ('free', 0), ('alloc', 0), ('alloc', 8)])

Expected Output: [0, -1, 0, 1, -1, 0]

Explanation: With alignment 8, any positive allocation needs the whole 8-byte block. The second allocation fails, freeing pointer 4 is invalid, allocating size 0 is invalid, and after freeing pointer 0 the 8-byte block can be allocated again.

Input: (32, 4, [('alloc', 4), ('alloc', 4), ('alloc', 4), ('alloc', 4), ('free', 8), ('free', 0), ('alloc', 8), ('free', 4), ('free', 12), ('free', 8), ('alloc', 16)])

Expected Output: [0, 4, 8, 12, 1, 1, 16, 1, 1, 0, 0]

Explanation: Four 4-byte blocks fill the left half of memory. After selective frees, the allocator must coalesce multiple levels correctly. The attempt to free 8 a second time is a double-free and returns 0.

Input: (32, 8, [('alloc', 3), ('alloc', 9), ('free', 0), ('alloc', 8), ('free', 16), ('free', 0), ('alloc', 24)])

Expected Output: [0, 16, 1, 0, 1, 1, 0]

Explanation: Alignment 8 forces the first request to use an 8-byte block. The 9-byte request rounds to 16. After freeing and coalescing all buddies back to a 32-byte block, the 24-byte request rounds to 32 and gets pointer 0.

Solution

def solution(capacity, alignment, operations):
    import heapq

    def next_power_of_two(x):
        if x <= 1:
            return 1
        return 1 << ((x - 1).bit_length())

    max_order = capacity.bit_length() - 1
    free_sets = [set() for _ in range(max_order + 1)]
    free_heaps = [[] for _ in range(max_order + 1)]

    def add_free(order, start):
        free_sets[order].add(start)
        heapq.heappush(free_heaps[order], start)

    def pop_free(order):
        heap = free_heaps[order]
        blocks = free_sets[order]
        while heap and heap[0] not in blocks:
            heapq.heappop(heap)
        if not heap:
            return None
        start = heapq.heappop(heap)
        blocks.remove(start)
        return start

    add_free(max_order, 0)
    allocated = {}
    result = []

    for op, value in operations:
        if op == 'alloc':
            size = value
            if size <= 0:
                result.append(-1)
                continue

            block_size = max(alignment, next_power_of_two(size))
            if block_size > capacity:
                result.append(-1)
                continue

            target_order = block_size.bit_length() - 1
            order = target_order
            while order <= max_order and not free_sets[order]:
                order += 1

            if order > max_order:
                result.append(-1)
                continue

            start = pop_free(order)

            while order > target_order:
                order -= 1
                half_size = 1 << order
                right_start = start + half_size
                add_free(order, right_start)

            allocated[start] = target_order
            result.append(start)

        elif op == 'free':
            ptr = value
            if ptr not in allocated:
                result.append(0)
                continue

            order = allocated.pop(ptr)
            start = ptr

            while order < max_order:
                buddy = start ^ (1 << order)
                if buddy in free_sets[order]:
                    free_sets[order].remove(buddy)
                    start = min(start, buddy)
                    order += 1
                else:
                    break

            add_free(order, start)
            result.append(1)

        else:
            result.append(-1)

    return result

Time complexity: O(log(capacity / alignment) * log F) amortized per operation, where F is the number of free blocks tracked in the heaps. Space complexity: O(A + F), where A is the number of currently allocated blocks and F is the number of tracked free blocks.

Hints

  1. Think in powers of two: each allocation belongs to a size class, and larger blocks can be split until the needed class is reached.
  2. When freeing a block of size S at address ptr, its buddy's address is ptr XOR S. If that buddy is also free, they can be merged.
Last updated: Apr 27, 2026

Loading coding console...

PracHub

Master your tech interviews with 7,500+ real questions from top companies.

Product

  • Questions
  • Learning Tracks
  • Interview Guides
  • Resources
  • Premium
  • For Universities
  • Student Access

Browse

  • By Company
  • By Role
  • By Category
  • Topic Hubs
  • SQL Questions
  • Compare Platforms
  • Discord Community

Support

  • support@prachub.com
  • (916) 541-4762

Legal

  • Privacy Policy
  • Terms of Service
  • About Us

© 2026 PracHub. All rights reserved.

Related Coding Questions

  • Compute Plant Infection Time - OpenAI (medium)
  • Implement IP Address Arithmetic - OpenAI (hard)
  • Simulate Infection Spread on a Grid - OpenAI (hard)
  • Implement Social Follow Recommendations - OpenAI (medium)
  • Build a Compose Rating Card - OpenAI (medium)