Comparison of Java and Go Garbage Collection Mechanisms
This article compares the memory management and garbage collection architectures of Java and Go, detailing their heap and stack regions, GC trigger conditions, collection algorithms, fragmentation handling, root object selection, and write‑barrier strategies, and includes illustrative code examples.
1. Garbage Collection Areas
Java manages memory primarily in the heap and method area, while Go uses a separate heap and stack. The heap and method area are the main regions handled by the Java GC, whereas Go’s GC focuses on the heap.
2. GC Trigger Timing
Java triggers GC when the application is idle, when the heap is insufficient, or when specific generation thresholds are crossed (e.g., Eden space, promotion to old generation, explicit System.gc()). Go triggers GC on runtime.mallocgc allocation, manual runtime.GC calls, and periodic runtime.forcegchelper checks.
3. Collection Algorithms
Java uses a generational approach: young generation employs a mark‑copy algorithm, while the old generation uses mark‑sweep or mark‑compact. Go primarily uses a mark‑sweep algorithm.
4. Fragmentation Handling
Java mitigates fragmentation through space compaction, generational collection, and region‑based designs (e.g., G1). Go reduces fragmentation via a span‑based memory pool, tcmalloc‑style size classes, and by allocating short‑lived objects on the stack when escape analysis permits.
5. GC Roots Selection
Java roots include stack frames, native stacks, static fields, constant pool references, internal VM references, and objects held by synchronized locks. Go roots are simpler: global variables and pointers in goroutine stacks.
6. Write Barriers
Both runtimes use write barriers to maintain tri‑color marking invariants. Java employs Dijkstra insertion and Yuasa deletion barriers (e.g., CMS, G1, Shenandoah). Go combined both approaches after v1.8, applying barriers only to the heap while the stack remains barrier‑free.
7. Summary Table
GC Area
Java: Heap & Method Area
Go: Heap
Trigger Timing
Java: many points due to generational collection
Go: allocation, manual, periodic
Algorithm
Generational – mark‑copy (young), mark‑sweep/compact (old)
Mark‑sweep
Fragmentation Solution
Compaction, object movement, region design
Span pool, tcmalloc, stack allocation
Code Example: Escape Analysis in Go
func F() {
temp := make([]int, 0, 20) // allocated on stack
temp = append(temp, 1)
}
func main() {
F()
}Running go build -gcflags=-m shows that temp does not escape and is allocated on the stack.
hewittwang@HEWITTWANG-MB0 rtx % go build -gcflags=-m
# hello
./new1.go:4:6: can inline F
./new1.go:9:6: can inline main
./new1.go:10:3: inlining call to F
./new1.go:5:14: make([]int, 0, 20) does not escapeWhen temp is passed to fmt.Print, escape analysis determines it must be allocated on the heap, increasing GC pressure.
hewittwang@HEWITTWANG-MB0 rtx % go build -gcflags=-m
# hello
./new1.go:9:11: inlining call to fmt.Print
./new1.go:12:6: can inline main
./new1.go:8:14: make([]int, 0, 20) escapes to heap
./new1.go:9:11: temp escapes to heapAuthor
Wang Hui, Tencent Backend Engineer, Nanjing University Software School graduate.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
