Documentation
¶
Overview ¶
Package snapshotgraph turns a parsed heapsnapshot.HeapSnapshot into a compact process-wide object graph with per-goroutine and process-global reachability sets.
The package does not depend on Delve and does not parse heap dumps itself. It only resolves raw pointer addresses produced by the heap dump parser into object IDs, builds graph edges, and walks the graph.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ComputeReachability ¶
func ComputeReachability(a *Analysis)
ComputeReachability walks the graph from every goroutine's roots and from the global roots, filling GoroutineReachability.Reachable, GlobalReachability.Reachable, and the reach-derived counters in Stats (GoroutineReachableObjects, GlobalReachableObjects, SharedByGoroutinesObjects, UnreachableObjects).
ComputeReachability is optional: Build no longer calls it. Callers that need whole-process reachability (diagnostics, offline analysis) should run it immediately after Build. The /debug/memusage handler skips this in favour of a single union BFS over only the goroutines whose labels match the request selector.
Idempotent: running ComputeReachability twice yields the same sets and stats.
func ReachableFrom ¶
ReachableFrom walks the graph iteratively starting from each root and returns the set of object IDs reachable from any of them. It handles cycles, self-edges, and shared objects. Invalid object IDs in roots or in Children edges are skipped rather than panicking.
Types ¶
type Analysis ¶
type Analysis struct {
Graph *Graph
Goroutines []GoroutineReachability
Globals GlobalReachability
Warnings []string
Stats Stats
}
Analysis is the full output of Build: a resolved object graph plus reachability sets and summary stats.
func Build ¶
func Build(snap *heapsnapshot.HeapSnapshot, opts Options) (*Analysis, error)
Build converts a parsed HeapSnapshot into an Analysis. It resolves pointer values to object IDs (supporting interior pointers), builds graph edges with deduplication, and extracts goroutine and global roots.
Build is structural only: it does not walk the graph. Reachability sets (GoroutineReachability.Reachable, GlobalReachability.Reachable) and reach-derived Stats (GoroutineReachableObjects, GlobalReachableObjects, SharedByGoroutinesObjects, UnreachableObjects) are populated by ComputeReachability. Callers that need whole-process reachability should call ComputeReachability immediately after Build. Callers that only need reachability for a label-selected subset of goroutines (the /debug/memusage handler) should skip ComputeReachability and traverse from the union of matched goroutine roots instead, paying for one BFS rather than one per goroutine plus globals.
Parser-level warnings from snap.Warnings are forwarded to Analysis.Warnings with a "parse: " prefix so downstream consumers see every recoverable problem in one place.
type GlobalReachability ¶
GlobalReachability is the reachability set rooted at process-wide roots: data, bss, otherroot, finalizer, queued_finalizer.
Reachable is populated by ComputeReachability, not Build.
type GoroutineReachability ¶
type GoroutineReachability struct {
GoroutineID uint64
IsSystem bool
IsBackground bool
Roots []RootRef
Reachable map[ObjectID]struct{}
}
GoroutineReachability is the reachability set rooted at a single goroutine's stack roots.
IsSystem and IsBackground are forwarded from the parsed goroutine record. Runtime-internal goroutines (g0, GC workers, the finalizer goroutine, etc.) hold pointers into runtime metadata that can pollute per-goroutine attribution if folded into user-visible bubbles. Phase 4 keeps them in the analysis but tags them so later phases can filter.
Reachable is populated by ComputeReachability, not Build. Callers that only need a label-selected subset (e.g. /debug/memusage) can ignore it and walk the graph themselves from Roots.
type Graph ¶
type Graph struct {
Objects []Object
ByAddr map[uint64]ObjectID
// contains filtered or unexported fields
}
Graph holds the compact process-wide object graph.
func (*Graph) FindObjectContaining ¶
FindObjectContaining resolves a non-zero pointer value to the object that contains it. The lookup supports interior pointers: a pointer somewhere inside an object's payload still resolves to that object. Address zero is treated as nil and never resolves.
type ObjectID ¶
type ObjectID uint32
ObjectID identifies one object in a Graph. It is also the object's index in Graph.Objects.
type ObjectRange ¶
ObjectRange is one half-open address range [Start, End) covered by a single object. Used for interior-pointer resolution. Zero-sized objects are intentionally not registered as ranges.
type Options ¶
type Options struct {
Strict bool
}
Options tunes the builder. Strict turns warnings into errors.
type RootRef ¶
RootRef is one resolved pointer from a stack frame, global root, or finalizer record into a heap object.
type Stats ¶
type Stats struct {
Objects int
ObjectBytes uint64
Edges int
RawObjectPointers int
ZeroObjectPointers int
ResolvedObjectPointers int
UnresolvedPointers int
UnresolvedObjectPointers int
UnresolvedGoroutineRoots int
UnresolvedGlobalRoots int
UnresolvedFinalizerRoots int
Goroutines int
SystemGoroutines int
GoroutineRootPointers int
GlobalRoots int
GoroutineReachableObjects int
GlobalReachableObjects int
UnreachableObjects int
}
Stats aggregates counters across the analysis.
Pointer accounting (object pointer slots):
RawObjectPointers = total pointer values seen in object slots,
including zero pointers
ZeroObjectPointers = how many of those were zero (nil)
ResolvedObjectPointers = non-zero pointers that resolved to a heap
object (pre-dedup)
UnresolvedObjectPointers = non-zero pointers that did not resolve
Edges = deduplicated child edges in the graph
Invariant:
RawObjectPointers = ZeroObjectPointers + ResolvedObjectPointers + UnresolvedObjectPointers
(Iface/eface data-word edges are decoded at the parser level — see ParseStats.InterfaceFieldsDecoded / EfaceFieldsDecoded — and included in PointerAddrs before the graph builder runs, so they contribute to RawObjectPointers. For current Go runtime versions these counts are always zero because the dump writer only emits fieldKindPtr from GC bitmaps.)
Root accounting tracks unresolved root pointers separately by source category so it is clear whether missing reachability is due to objects, goroutine stacks, globals, or finalizers.