Hone logo
Hone
Problems

Implementing a Basic Mark and Sweep Garbage Collector in Go

This challenge asks you to implement a simplified version of the mark and sweep garbage collection algorithm in Go. Garbage collection is a crucial aspect of memory management in many programming languages, automatically reclaiming memory that is no longer in use. This exercise will help you understand the core principles behind this important technique.

Problem Description

You are tasked with creating a rudimentary mark and sweep garbage collector. The collector will manage a pool of objects, tracking their reachability from a set of root objects. The algorithm should identify and reclaim memory occupied by objects that are no longer reachable.

What needs to be achieved:

  1. Object Representation: Define a structure to represent an object in memory. This structure should include a pointer to data and a flag to indicate whether the object has been marked.
  2. Root Objects: Maintain a slice of root objects. These are objects considered always reachable and serve as the starting point for the marking phase.
  3. Mark Phase: Implement the mark phase of the algorithm. Starting from the root objects, recursively traverse the object graph, marking each reachable object.
  4. Sweep Phase: Implement the sweep phase. Iterate through all objects in the memory pool. Any object that has not been marked during the mark phase is considered garbage and should be reclaimed (in this simplified version, simply remove it from the managed pool).
  5. Object Allocation: Provide a function to allocate new objects and add them to the managed pool. This function should return a pointer to the newly allocated object.
  6. Object Linking: Provide a function to link two objects together. This function should set a field in one object to point to another.

Key Requirements:

  • The collector should correctly identify and reclaim unreachable objects.
  • The collector should not reclaim reachable objects.
  • The collector should handle cycles in the object graph correctly (i.e., objects referencing each other).
  • The allocation and linking functions should be safe and prevent memory corruption.

Expected Behavior:

The collector should operate as follows:

  1. Objects are allocated and added to a managed pool.
  2. Objects can be linked together to form a graph.
  3. When the garbage collection is triggered, the mark phase identifies all reachable objects from the root objects.
  4. The sweep phase removes all objects that were not marked, effectively reclaiming their memory.

Edge Cases to Consider:

  • Cycles: Objects referencing each other in a circular dependency.
  • Root Objects: Ensure root objects are always reachable and not accidentally collected.
  • Empty Pool: Handle the case where the object pool is empty.
  • No Reachable Objects: Handle the case where all objects are unreachable.

Examples

Example 1:

Input:
  - Root Object: obj1
  - Objects: obj1, obj2, obj3, obj4
  - Links: obj1 -> obj2, obj2 -> obj3, obj3 -> obj1, obj4 -> nil
  - Garbage Collection Triggered

Output:
  - Managed Pool: [obj1, obj2, obj3]
  - Reclaimed: [obj4]
Explanation: obj1, obj2, and obj3 form a cycle and are reachable from the root object. obj4 is not reachable and is reclaimed.

Example 2:

Input:
  - Root Object: obj1
  - Objects: obj1, obj2, obj3
  - Links: obj1 -> obj2
  - Garbage Collection Triggered

Output:
  - Managed Pool: [obj1, obj2]
  - Reclaimed: [obj3]
Explanation: obj1 and obj2 are reachable from the root object. obj3 is not reachable and is reclaimed.

Example 3: (Edge Case - No Reachable Objects)

Input:
  - Root Object: nil
  - Objects: obj1, obj2, obj3
  - Links: None
  - Garbage Collection Triggered

Output:
  - Managed Pool: []
  - Reclaimed: [obj1, obj2, obj3]
Explanation: Since there are no root objects, all objects are unreachable and are reclaimed.

Constraints

  • Object Size: Assume each object occupies a fixed size of 64 bytes. You don't need to implement dynamic memory allocation within each object; just manage pointers to data.
  • Pool Size: The maximum number of objects in the managed pool is 100.
  • Performance: While correctness is paramount, strive for reasonable efficiency in the mark and sweep phases. Avoid unnecessary iterations.
  • Input Format: The input for the example scenarios is conceptual. You will need to implement the object allocation, linking, and garbage collection functions to test your implementation.

Notes

  • This is a simplified implementation. Real-world garbage collectors are significantly more complex and incorporate optimizations like generational collection and concurrent marking.
  • Focus on the core mark and sweep algorithm. You don't need to implement a full-fledged memory allocator.
  • Consider using a map to store the objects for efficient lookup during the sweep phase.
  • The mark function should be recursive.
  • The sweep function should iterate through the managed objects and remove the unmarked ones.
  • Think about how to represent the object graph and how to traverse it during the mark phase.
  • Error handling is not required for this exercise.
Loading editor...
go