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

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

Memory fragmentation can make allocation less efficient, but a large heap or rising process memory alone does not prove it is happening. Diagnose it by separating free gaps from live objects, then comparing fragmentation, allocation, collection, pause, and process-memory measurements at consistent points in the same workload.

What fragmentation is—and what it is not

A garbage collector can reclaim objects that are no longer reachable. Compaction is a separate operation: it moves reachable objects closer together so free space is less divided. Collectors do not necessarily compact on every collection, and some objects or heap regions may not be movable.

Fragmentation is unused space left in gaps among live objects. A gap can be useful if a new allocation fits, but a larger request may not fit there. The effect therefore depends on the sizes and timing of allocations, the heap region involved, and whether that runtime can move the objects surrounding a gap.

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

A large live set is different: it is memory occupied by reachable objects, which the collector cannot reclaim. A high allocation rate is another distinct condition; it can cause collections to happen more often even if fragmentation is not the problem. These conditions can coexist, so heap size by itself cannot distinguish them.

Why memory may remain high after a collection

Collection does not guarantee that a runtime returns memory to the operating system or that the heap becomes smaller. For example, .NET workstation GC with concurrent collection does not compact reclaimed objects, and heap size may remain the same or appear larger. Committed virtual memory can also exceed the heap size because it includes memory ready for allocation.

Keep live heap, fragmentation, committed memory, virtual address space, resident memory (RSS), and total process memory as separate measurements. Their meanings differ; treating them all as “memory usage” can make normal reservation or retention look like a leak.

How to tell whether fragmentation is affecting your application

Look for a pattern across multiple comparable observations, not one large number. Capture measurements around collection events using the same workload and timing. A useful view includes:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • Heap size and, where available, post-collection live-heap data.
  • Fragmentation bytes or a runtime-specific fragmentation ratio, broken down by relevant generation or heap region.
  • Allocation rate and collection frequency.
  • Pause duration and percentiles, alongside service latency and throughput.
  • Process RSS and the runtime’s committed or virtual-memory measurements, clearly labeled.

Evidence is stronger when fragmentation is elevated in the part of the heap relevant to the failing allocations and the pattern coincides with allocation difficulty or pressure. A high heap with a large live set, frequent collections, or high RSS can have other explanations. Check those measurements before attributing the symptom to fragmentation.

.NET: inspect generations, pinned objects, and the LOH

.NET exposes fragmentation and heap-size information by generation. Its performance guidance describes fragmentation as free space divided by total allocated memory for a generation, and recommends considering the generation 2 ratio rather than relying only on an absolute byte count. Pinned objects can contribute because the collector cannot move them while they remain pinned. Frequent loading and unloading of small assemblies, many COM references, and large transient objects are also documented diagnostic leads for fragmentation or difficulty allocating segments; they are possibilities to investigate, not proof of a cause.

Metrics and version checks

Starting with .NET 9, the runtime metrics documentation lists dotnet.gc.last_collection.heap.size and dotnet.gc.last_collection.heap.fragmentation.size. They are tagged by heap generation, including gen0, gen1, gen2, LOH, and POH. Confirm that the deployed runtime supports these metrics and verify their semantics before building dashboards or alert thresholds. Fragmentation bytes are not necessarily unusable: a gap can be reused when the next allocation fits, and a special compacting collection can move live objects when they are not pinned.

Large object heap behavior

The .NET documentation describes 85,000 bytes as the default threshold for allocation to the large object heap (LOH). This is a .NET implementation detail, not a rule for Go or Java; check the deployed .NET version and configuration. The LOH is ordinarily not compacted because moving large objects is costly. On-demand LOH compaction is documented for .NET Core and .NET Framework 4.5.1 and later.

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

When investigating large transient allocations, relate allocation sizes and timing to LOH measurements rather than inferring LOH fragmentation from total process memory. Avoid calling GC.Collect as a routine fix: the .NET fundamentals guidance says manual collection is unnecessary in almost all cases because the collector runs continuously.

Go: measure heap, pauses, and memory-limit effects

Go uses a tracing garbage collector. Its GOGC setting controls a memory-versus-CPU tradeoff: increasing it reduces GC CPU overhead but increases peak memory in proportion to the live heap; lowering it reduces peak memory at the cost of more GC CPU overhead. The right balance depends on the service’s memory and latency constraints, not on a universal setting.

The Go memory limit can cause collections to run more frequently. The limit is soft, but setting it too close to the live set can lead to GC thrashing and poor progress. If memory rises or throughput falls after changing the limit or GOGC, compare live-heap size, collection frequency, GC CPU, RSS, and service latency under the same representative load.

Built-in diagnostic options

  • runtime.ReadMemStats reports heap allocation and GC metrics.
  • debug.ReadGCStats reports GC pause statistics and percentiles.
  • GODEBUG=gctrace=1 prints collection events, including memory collected and pause length.
  • A heap dump captures allocated objects and runtime state, but suspends goroutines while it is written. Account for that operational impact before collecting one from a live service.

Go may reserve virtual address space, so VSS can be misleading as an indicator of physical memory use. Give RSS and similar physical-memory measures their own labels rather than conflating them with virtual reservations or live heap.

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

Java 24 G1: weigh pause goals against throughput

Oracle’s Java 24 documentation describes G1 as a collector for multiprocessor systems and large amounts of memory, including heaps with significant fragmentation and variable allocation or promotion rates. G1 aims to meet pause-time goals while maintaining throughput. Its concurrent work consumes processor resources that could otherwise be used by the application, and throughput may be somewhat lower than with throughput collectors.

Assess G1 against the application’s actual pause and throughput goals. These characteristics are specific to the cited Java 24 G1 documentation; they do not make G1’s heap layout, measurements, or controls interchangeable with .NET or Go.

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

A practical investigation sequence

  1. Identify the environment. Record the runtime and version, collector, operating system, container or process memory limit, and the exact meaning of each memory reading: heap, committed, virtual, resident, or total process memory.
  2. Choose a representative observation window. Use a repeatable workload and collect allocation rate, post-collection heap or live-set data, fragmentation by relevant generation or region, collection frequency, pause durations and percentiles, and process RSS. Compare snapshots taken at equivalent points in the collection cycle.
  3. Check the runtime-specific suspects. For .NET, examine pinning, LOH behavior, and large transient allocations. For Go, review live-heap growth and the interaction between GOGC and the memory limit. For Java 24 G1, evaluate pause goals and the throughput cost of concurrent work.
  4. Change one relevant factor at a time. Test under production-like load and compare memory alongside service-level latency and throughput. Keep the runtime-specific measurements and workload constant so the effect of a change is interpretable.

How to choose the next step

  • If the live set is growing, investigate what remains reachable before trying to compact the heap.
  • If allocations and collections are frequent but fragmentation is not elevated, inspect allocation rate and runtime-specific GC tradeoffs.
  • If fragmentation is elevated in a relevant heap region, check whether the runtime can compact that region and whether pinned or otherwise immovable objects constrain it.
  • If process memory is high while heap measurements are not, first reconcile RSS, committed memory, virtual reservations, and container limits.
  • If pauses are the primary symptom, evaluate pause percentiles and throughput together; reducing one cost can increase another.

No single fragmentation threshold or GC setting applies across these runtimes. A useful diagnosis ties a runtime-specific measurement to the allocation pattern and service symptom it is meant to explain.

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.

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.