KERNEL PANIC

FATAL_ERROR: RED_BULL_RESERVOIR_EMPTY

A problem has been detected and systems have been shut down to prevent damage to your sanity.


*** STOP: 0x000000GO (0x000000RU, 0x000000ST, 0x000000SRE, 0x000000AI)


Rebooting in 5 seconds...

Originally published on multiple external platforms.

Go is a statically typed, garbage collected language, much like Java, Python, or C#. In this blog, we’ll dive deeper into how Go manages memory and what happens during a garbage collection cycle.

What is Garbage Collection and Why is it needed?

In programming, garbage refers to allocated memory space that is no longer reachable or usable by the program.

When a program executes, it primarily uses two parts of memory: the Stack and the Heap.

type RandomBox struct {
    ID   int
    Name string
}

func GenerateRandomBox() *RandomBox {
    // 'ref' is allocated on the stack
    // The struct itself escapes to the heap
    ref := &RandomBox{ID: 1, Name: "Rust"}
    return ref
}

func main() {
    box := GenerateRandomBox()
    fmt.Println(box.Name)
}

Go uses Escape Analysis to determine whether a variable can stay on the stack or must “escape” to the heap. When a reference to heap memory is lost, that memory becomes garbage and must be cleaned up.

Memory Reference lost

The Go Garbage Collector

Go uses a concurrent mark and sweep garbage collector. It is called concurrent because it can run in parallel with your main application code, minimizing pauses.

The GC Phases

When the compiler decides it’s time to run a collection cycle, it follows these steps:

1. Mark Setup (STW) The collector initiates a Stop The World (STW) event. This briefly pauses all goroutines to enable the write barrier, ensuring that no data is lost or corrupted while the collector is working.

GC Mark Setup

2. Marking (Concurrent) In this phase:

  • The collector inspects stacks to find root pointers into the heap.
  • It traverses the heap to identify objects currently in use.
  • The collector uses 25% of available CPU power (e.g., 1 out of 4 threads).

Mark Assist: If an application goroutine is allocating memory faster than the collector can mark it, the collector may recruit that goroutine to help with the marking process.

GC Marking

3. Mark Termination (STW) Another brief STW event occurs to turn off the write barrier, perform final cleanup, and calculate the schedule for the next GC run. The goal is to keep these STW pauses under 100ms.


Sweeping and Triggers

Sweeping is the process of reclaiming memory from objects that were not marked as being in use. Interestingly, sweeping happens outside the main GC cycle—typically when a new memory allocation is requested—so it doesn’t add to the GC latency.

GC Sweeping Visualization

What triggers a GC run?

  1. Heap Growth: By default, GC runs when the heap doubles in size from the previous run.
  2. Time Interval: If a collection hasn’t run for more than two minutes, one is forced.
  3. Manual Trigger: You can call runtime.GC() manually (though rarely recommended).
  4. Allocation Threshold: Large allocations in runtime.mallocgc can also trigger a run.

Tuning the Collector

Go’s philosophy is to keep tuning simple. Developers have one primary knob: the GOGC environment variable (or debug.SetGCPercent). The default is 100, meaning GC triggers when the heap grows by 100%.

GC Tuning

The GC Pacer

The GC Pacer algorithm continuously monitors the application and may start a collection earlier than scheduled if it determines that doing so will provide a better performance benefit.

Happy Learning!!

36.5°C
CORE TEMPERATURE

KERNEL PANIC

Critical system failure. All Gophers have escaped.

Rebooting universe in 5...

Error: PEBKAC_EXCEPTION
Address: 0xDEADBEEF