Class 26: Closure & Go Internal Memory Deep Dive ๐Ÿ’ก

Welcome to Class 26, where we uncover the magic behind closures in Go, escape analysis, and how memory is managed under the hood! ๐Ÿง ๐Ÿ”ฅ


๐Ÿงพ The Code

package main

import "fmt"

const a = 10
var p = 100

//Closure
func outer(money int) func() {
	age := 30
	fmt.Println("Age =", age)

	show := func() {
		money = money + a + p
		fmt.Println(money)
	}

	return show
}

func call() {
	incr1 := outer(100)
	incr1() // money = 100 + 10 + 100 = 210
	incr1() // money = 210 + 10 + 100 = 320

	incr2 := outer(100)
	incr2()
	incr2()
}

func main() {
	call()
}

func init() {
	fmt.Println("=== Bank ===")
}

๐Ÿ” Key Concepts

๐Ÿ”’ What is a Closure?

A closure is a function that references variables from outside its own scope. In this case:

show := func() {
    money = money + a + p
    fmt.Println(money)
}

show forms a closure by capturing the money variable defined in outer().

๐Ÿง  Why is Closure Important?

Closures let you encapsulate logic along with state. This is why incr1() and incr2() maintain separate money values even though they use the same function.

๐Ÿงฎ Stack vs Heap

  • Stack: Fast memory, used for function calls and local variables.
  • Heap: Used when variables need to persist beyond the function call (like in closures!).

Because money needs to stick around after outer() returns, escape analysis detects this and allocates money on the heap.

๐Ÿงช What is Escape Analysis?

Escape analysis is the process that the Go compiler uses during the compilation phase to determine whether variables can be safely allocated on the stack or must go to the heap.

  • โœ… If a variable is used only inside a function, it's put on the stack.
  • ๐Ÿš€ If a variable is used outside (like in a returned closure), it's moved to the heap.

๐Ÿงฑ Memory Segments

SegmentWhat's Stored
Code SegmentCompiled instructions (functions)
Data SegmentGlobal and static variables (a, p)
StackLocal variables (age)
HeapEscaping variables (money)

๐Ÿง  Visualization

CLI-Style Memory Layout

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚       Code Segment          โ”‚
โ”‚-----------------------------โ”‚
โ”‚ main, call, init, outer,    โ”‚
โ”‚ anonymous show function     โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
          โ†“
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚       Data Segment          โ”‚
โ”‚-----------------------------โ”‚
โ”‚ const a = 10                โ”‚
โ”‚ var p = 100                 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
          โ†“
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚           Stack             โ”‚
โ”‚-----------------------------โ”‚
โ”‚ outer() frame               โ”‚
โ”‚   age = 30                  โ”‚
โ”‚   return address            โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
          โ†“
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚            Heap             โ”‚
โ”‚-----------------------------โ”‚
โ”‚ money = 100 (for incr1)     โ”‚
โ”‚ money = 100 (for incr2)     โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Each closure has its own money on the heap. Every call to outer(100) results in a new memory block being allocated.

Garbage Collectorโ€™s Role ๐Ÿงน

When the closure is no longer referenced (e.g., incr1 or incr2 goes out of scope), the Garbage Collector detects that the heap memory (e.g., money) is unreachable. It then safely reclaims that memory so your program doesnโ€™t become a memory hoarder. This is vital for maintaining efficiency, especially when many closures are involved.

GC is triggered automatically and runs concurrently with your program. It uses a combination of mark-and-sweep and concurrent garbage collection techniques to do this efficiently.


๐Ÿง  TL;DR

  • Closures can capture and remember variable state ๐Ÿ”
  • Escape analysis figures out which variables must live on the heap ๐Ÿ“ฆ
  • Stack is temporary, heap is persistent (with GC ๐Ÿงน)
  • Go separates memory into Code, Data, Stack, Heap โ€” each with its role ๐Ÿงฉ
  • GC ensures unused heap memory (like old closure data) is recycled โ™ป๏ธ