Hone logo
Hone
Problems

Simulating a Basic Memory Model in Go

This challenge asks you to implement a simplified memory model in Go. Understanding how memory is managed is crucial for writing efficient and reliable Go programs, especially when dealing with concurrency and resource allocation. This exercise will help you grasp the fundamental concepts of memory allocation, deallocation, and tracking memory usage.

Problem Description

You are tasked with creating a MemoryModel struct in Go that simulates a simplified memory space. This model should allow you to allocate blocks of memory, deallocate them, and track the total memory currently in use. The model should handle allocation requests, prevent double-freeing, and manage a contiguous block of memory.

Key Requirements:

  • Allocation: The Allocate(size int) (int, error) method should allocate a block of size bytes from the memory pool. It should return the starting address of the allocated block and nil if successful. If there's not enough contiguous space, it should return an error.
  • Deallocation: The Deallocate(address int) method should deallocate the memory block starting at the given address. It should return an error if the address is invalid (not allocated or already freed).
  • Usage Tracking: The Usage() method should return the total number of bytes currently allocated in the memory model.
  • Error Handling: Appropriate errors should be returned for invalid allocation/deallocation requests (e.g., out of memory, double free, invalid address).
  • Contiguous Memory: The memory model should maintain a contiguous block of available memory. Allocation should occur from the beginning of the available space, and deallocation should mark the block as free without shifting other blocks.

Expected Behavior:

The MemoryModel should behave as a simplified memory manager, ensuring that allocations are valid, deallocations are safe, and memory usage is tracked accurately. The model should prevent memory leaks and double frees.

Edge Cases to Consider:

  • Allocation requests larger than the available memory.
  • Deallocating an address that was never allocated.
  • Deallocating the same address twice (double free).
  • Allocation requests of size 0.
  • Deallocation of an address that is part of an already allocated block.

Examples

Example 1:

Input:
  - Initial memory pool size: 100
  - Allocate(20)
  - Allocate(30)
  - Deallocate(0)
  - Usage()
Output:
  - Allocated address 1: 0
  - Allocated address 2: 20
  - Usage(): 50
Explanation: The first allocation takes 20 bytes starting at address 0. The second takes 30 bytes starting at address 20. Deallocating address 0 frees 20 bytes. The total usage is now 30 bytes.

Example 2:

Input:
  - Initial memory pool size: 50
  - Allocate(20)
  - Allocate(30)
Output:
  - Allocated address 1: 0
  - Error: allocate: not enough memory
Explanation: The first allocation takes 20 bytes starting at address 0. The second allocation request for 30 bytes fails because there's only 30 bytes left (50 - 20).

Example 3:

Input:
  - Initial memory pool size: 100
  - Allocate(50)
  - Deallocate(0)
  - Deallocate(0)
Output:
  - Error: deallocate: invalid address
Explanation: Deallocating address 0 a second time results in an error because the memory has already been freed.

Constraints

  • The initial memory pool size will be between 10 and 1000 bytes (inclusive).
  • Allocation sizes will be between 0 and the remaining available memory (inclusive).
  • Addresses will be non-negative integers.
  • The solution should be reasonably efficient; avoid unnecessary memory copying or complex data structures. A simple linear search for free blocks is acceptable.
  • The Usage() method should return the correct memory usage in bytes.

Notes

  • You don't need to implement a sophisticated memory allocation algorithm (e.g., best-fit, first-fit). A simple approach of allocating from the beginning of the available memory is sufficient.
  • Focus on correctness and error handling.
  • Consider using a slice to represent the memory pool.
  • Think about how to track allocated and free blocks within the memory pool. A simple boolean flag for each block can be used.
  • The addresses returned by Allocate are indices into the underlying memory pool slice.
Loading editor...
go