Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A tracing garbage collector follows references from live roots, then makes unreachable object storage available for reuse. Concurrent collectors must account for references changing during that process, while the runtime and operating system may keep memory resident afterward. That is why a successful collection does not necessarily lower a process’s RSS.

What happens during a garbage-collection cycle?

A tracing collector determines which managed objects are reachable by starting at roots—such as global variables and references held by active stacks—and following pointers from them. In a mark-sweep design, it marks the objects it finds, then sweeps through managed storage: objects not found by the trace can be reclaimed for later allocations. The Go project’s garbage-collector guide describes this pattern for the standard Go toolchain.

“Reclaimed” does not necessarily mean returned to the operating system. It means the runtime can reuse the storage; whether memory is subsequently released or removed from the process’s resident footprint is a separate question.

How does tri-color marking work?

Tri-color marking is a way to reason about the collector’s progress, not a claim that every runtime literally stores one of three color labels on every object:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • White: not yet discovered by the current trace.
  • Grey: discovered, but its references have not all been scanned.
  • Black: scanned; the collector has examined its outgoing references.

At the start of a cycle, objects can be treated as white. The collector shades roots grey, takes a grey object, scans its pointers, and shades newly discovered objects grey. Once it has scanned that object, it is black. When no grey work remains, white objects are candidates for reclamation, subject to the collector’s full algorithm and any other rules it uses.

In the Go project’s conceptual account of concurrent marking, a key invariant is that a black object must not point to a white object. Otherwise, the collector could have finished scanning the black object before the reference to the still-white object appeared, and might fail to discover an object that is reachable when marking ends. The account appears in “Go GC: Prioritizing low latency and simplicity”.

Why does a concurrent collector need a write barrier?

During concurrent marking, the application—the mutator—can continue changing pointers while the collector scans. A write barrier is work performed around relevant pointer updates so the collector’s view remains safe despite those changes. For example, in the Go article’s explanation, the barrier shades a newly reachable white object grey, ensuring it will be scanned.

As the Go project puts it: “Maintaining this invariant is the job of the write barrier, which is a small function run by the mutator whenever a pointer in the heap is modified.” The exact barrier strategy varies: collectors may use different barrier algorithms or combinations of synchronization and barriers. The Go article is a conceptual, historical explanation associated with the Go 1.5 collector, not a complete specification of current Go internals. Go’s runtime barrier source documents implementation details for the source version shown there.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Why can RSS stay high after garbage collection?

Several memory measures describe different things. A collection can reduce the live managed objects without reducing the process’s RSS, because reclaiming object storage, reusing heap pages, and changing operating-system residency are separate stages.

Measure or state What it tells you What it does not prove
Reachability Whether the collector can find an object by tracing from roots. Whether its storage has already been reclaimed.
Reclaimed or reusable storage Whether the runtime can use an object’s former storage for future allocations. That the runtime has returned the corresponding pages to the operating system.
Committed or reserved memory Memory or address space the runtime manages for its heap and internal needs. How much of it is currently resident in physical memory.
RSS Resident pages attributed to the process under the operating system’s accounting. How many managed objects are live; RSS can also include stacks, native allocations, mappings, and other runtime memory.

After objects become reusable, an allocator may retain their spans or pages for later allocations. A runtime may release memory gradually or only under particular conditions, and resident memory outside the managed heap may remain. These are possible explanations, not diagnoses: the exact behavior depends on the runtime, collector, operating system, and measurement method.

For Go specifically, the Go GC guide warns that virtual-memory measures such as VSS can be poor indicators of process footprint because the runtime may reserve large address-space regions; it recommends RSS and similar measures for physical-footprint assessment in that context. Do not infer that objects remain live from one high post-collection RSS reading alone. A live heap or retained-object graph that keeps growing at comparable post-collection points is more relevant evidence of retained objects; stable live-heap measurements alongside high RSS instead suggest investigating allocator retention, non-heap memory, and residency accounting.

What do Go and Java G1 illustrate—and what do they not?

Collector details are implementation-specific. The Go guide describes the standard gc compiler and toolchain and expressly identifies its account as describing Go 1.19. It is a useful source for that scope, not a guarantee about every Go implementation or all details of a current release. The Go 1.5 engineering article explains the tri-color and barrier concepts, but should not be read as a current benchmark or exhaustive description of today’s runtime.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

For a different example, Oracle’s Java 23 HotSpot garbage-collection tuning guide says G1 uses Snapshot-At-The-Beginning (SATB) marking and notes that it can retain some additional memory compared with other marking approaches. This demonstrates that marking strategy can affect temporary retention; it does not establish why a particular Java process has high RSS.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

How should you diagnose high memory use after a collection?

  1. Record the environment. Note the language and runtime version, collector configuration, operating system, container limit, and whether the process uses native code or memory-mapped files.
  2. Compare like with like. Measure at consistent points, including after a completed collection where possible. Record live heap or object-profile data, allocation and release metrics where available, runtime committed-memory measures, and OS or container RSS. Metrics with different definitions are not interchangeable.
  3. Check whether live memory is growing. Inspect a heap profile or retained-object graph, alongside runtime-specific GC logs and metrics. These can help distinguish retained objects from allocation churn and show collection frequency, work, pauses, or memory-release activity.
  4. Follow the evidence before tuning. If live heap is high, look for retaining references and allocation sources. If it is stable while RSS remains high, investigate runtime-retained pages, stacks, native allocations, mappings, and platform accounting before deciding that collection failed.
  5. Change one runtime-specific control at a time. Compare memory with CPU use and latency after each change. For Go, the guide discusses heap profiles, runtime metrics, GC traces, GOGC, and GOMEMLIMIT; those controls and their semantics should not be generalized to other runtimes. It describes the runtime memory limit as soft, so it is not a guarantee that process RSS will stay below a fixed number.

When comparing collectors or interpreting a memory graph, keep the runtime and collector version, marking and barrier strategy, pause time and CPU work, live versus allocated or committed heap, RSS versus virtual size, page-release behavior, and container limits in view. Without those details, two memory figures—or two collectors’ behavior—may not be meaningfully comparable.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.