Skip to main content

Go: Memory Allocation 内存分配

📅 2026-02-10 ✏️ 2026-03-14 Inside Go CS GO
No related notes

0.1 · Overview#

https://go.dev/ref/mem

Runtime manages memory allocation with a multi-layer caching strategy to reduce lock contention and fragmentation. The allocator is inspired by TCMalloc.

Memory States (runtime/mem.go):

  1. None - Default state of system memory
  2. Reserved - Owned by runtime, not accessible
  3. Prepared - ?
  4. Ready - Safely accessible

0.2 · Allocation Architecture#

0.2.1 · Hierarchy: mcache → mcentral → mheap → OS#

Small Objects (< 32KB):

  1. Round up to a size class (1B ~ 32KB, ~70 classes)
  2. Check P’s mcache for available mspan - no lock required
  3. If empty, fetch from mcentral (global, per-size class) - requires lock
  4. If mcentral is empty, fetch from mheap
  5. If mheap is insufficient, request from OS (at least 1MB via syscall)

Large Objects (> 32KB):

  • Bypass mcache and mcentral, allocate directly from mheap

0.2.2 · Size Classes#

Generated by mksizeclasses.go with 12.5% granularity between levels.

Classification:

  • Tiny (< 16 bytes, noscan): Multiple tiny allocations share a block
  • Small (16 bytes ~ 32 KB, or has pointer): Per-size-class span from mcache
  • Large (> 32 KB): Direct allocation from mheap

Span Strategy:

  • ~70 size classes (8 bytes ~ 32 KB)
  • Each size has two variants: scan (contains pointers) and noscan
  • Reduces fragmentation through span-based allocation

0.2.3 · Multi-Layer Caching#

Motivation: Reduce lock contention and allocation overhead

  1. mcache (Per-P, lock-free)

    • Each logical processor P maintains local mspan cache for each size class
    • No locking required for allocation
  2. mcentral (Global, fine-grained locks)

    • ~67 × 2 mspan lists (per size class)
    • Backs up mcache
  3. mheap (Global, coarse-grained lock)

    • Maintains free contiguous pages (via treap structure since Go 1.11)
    • Pages are merged when returned (coalescence)

0.2.4 · Span Reclamation#

When returning a span to mheap:

  1. If span is still allocated (contains live objects), place in mcentral for that size class
  2. If span is fully freed, return pages to mheap
  3. mheap merges contiguous free pages (treap structure)
  4. Periodic background goroutine returns excess memory to OS

0.3 · Virtual Memory Layout#

Arena-based hierarchy (64-bit: 64MB per arena, 32-bit: 4MB):

Memory Space

Arenas (64MB each on 64-bit)
  ├── heapArena (metadata for this arena)
  │   ├── Bitmap (marks for all words in arena)
  │   ├── Spans (page-to-span mapping for all pages in arena)
  │   └── Additional metadata
  └── mheap._arenas (2D mapping: L1 × many L2s)

Each arena is aligned, allowing efficient mapping via array indexing.

0.4 · Stack Allocation#

Multi-layer and multi-class strategy similar to heap:

  • Reduces allocation lock contention
  • Minimizes stack waste

0.5 · Memory Reclamation#

  • On-demand: When goroutine needs new span, it first attempts to reclaim memory by sweeping spans of same size
  • Background: sysmon periodically returns excess mheap memory to OS

0.5.1 · Sweep Mechanics#

When goroutine needs allocation:

  • For small span: Sweep same-size spans until at least one object is freed
  • For large span: Sweep spans until at least that many pages are freed to heap
  • Edge case: Sweeping may release non-contiguous single-page spans, still leaving gaps for larger allocations

0.6 · References#