Table of Contents
Fetching ...

Pathological Cases for a Class of Reachability-Based Garbage Collectors

Matthew Sotoudeh

TL;DR

The paper formalizes a mutator-observer model for garbage collection and proves that for any GC implementing this interface there exist pathological sequences that force either a superlogarithmic collection delay or a superlogarithmic pause, tying GC performance limits to dynamic graph reachability. It introduces the Garbage Collection Data Structure (GCDS) to capture the interaction between mutator updates and collector work, and proves a main lower bound that $t_{ ext{AR}}(n)d(n) = ilde{Omega}(\log^{3/2}{n})$, via a reduction from dynamic reachability (DRDS) with clocked machines and checkpoint-restores. A tighter, sparse-acyclic lower bound is developed showing $t_{ ext{S,A,AR}}(n)d(n) = ilde{Omega}(\log{n})$, and an upper-bound construction using an Euler Tour Data Structure achieves $d(n)=1$ and $t_{ ext{S,A,AR}}(n)=O(\log{n})$ in sparse, acyclic settings, illustrating a near-optimal acyclic-bound trade-off. The work discusses practical implications for real-time languages, presents an exploratory Lua implementation and benchmarks, and situates the results among existing GC theories and dynamic graph lower bounds, concluding that pathological worst-case behavior is unavoidable in general, thus motivating generational and type-system-based mitigations.

Abstract

Although existing garbage collectors (GCs) perform extremely well on typical programs, there still exist pathological programs for which modern GCs significantly degrade performance. This observation begs the question: might there exist a 'holy grail' GC algorithm, as yet undiscovered, guaranteeing both constant-length pause times and that memory is collected promptly upon becoming unreachable? For decades, researchers have understood that such a GC is not always possible, i.e., some pathological behavior is unavoidable when the program can make heap cycles and operates near the memory limit, regardless of the GC algorithm used. However, this understanding has until now been only informal, lacking a rigorous formal proof. This paper complements that informal understanding with a rigorous proof, showing with mathematical certainty that every GC that can implement a realistic mutator-observer interface has some pathological program that forces it to either introduce a long GC pause into program execution or reject an allocation even though there is available space. Hence, language designers must either accept these pathological scenarios and design heuristic approaches that minimize their impact (e.g., generational collection), or restrict programs and environments to a strict subset of the behaviors allowed by our mutator-observer-style interface (e.g., by enforcing a type system that disallows cycles or overprovisioning memory).

Pathological Cases for a Class of Reachability-Based Garbage Collectors

TL;DR

The paper formalizes a mutator-observer model for garbage collection and proves that for any GC implementing this interface there exist pathological sequences that force either a superlogarithmic collection delay or a superlogarithmic pause, tying GC performance limits to dynamic graph reachability. It introduces the Garbage Collection Data Structure (GCDS) to capture the interaction between mutator updates and collector work, and proves a main lower bound that , via a reduction from dynamic reachability (DRDS) with clocked machines and checkpoint-restores. A tighter, sparse-acyclic lower bound is developed showing , and an upper-bound construction using an Euler Tour Data Structure achieves and in sparse, acyclic settings, illustrating a near-optimal acyclic-bound trade-off. The work discusses practical implications for real-time languages, presents an exploratory Lua implementation and benchmarks, and situates the results among existing GC theories and dynamic graph lower bounds, concluding that pathological worst-case behavior is unavoidable in general, thus motivating generational and type-system-based mitigations.

Abstract

Although existing garbage collectors (GCs) perform extremely well on typical programs, there still exist pathological programs for which modern GCs significantly degrade performance. This observation begs the question: might there exist a 'holy grail' GC algorithm, as yet undiscovered, guaranteeing both constant-length pause times and that memory is collected promptly upon becoming unreachable? For decades, researchers have understood that such a GC is not always possible, i.e., some pathological behavior is unavoidable when the program can make heap cycles and operates near the memory limit, regardless of the GC algorithm used. However, this understanding has until now been only informal, lacking a rigorous formal proof. This paper complements that informal understanding with a rigorous proof, showing with mathematical certainty that every GC that can implement a realistic mutator-observer interface has some pathological program that forces it to either introduce a long GC pause into program execution or reject an allocation even though there is available space. Hence, language designers must either accept these pathological scenarios and design heuristic approaches that minimize their impact (e.g., generational collection), or restrict programs and environments to a strict subset of the behaviors allowed by our mutator-observer-style interface (e.g., by enforcing a type system that disallows cycles or overprovisioning memory).

Paper Structure

This paper contains 78 sections, 12 theorems, 6 equations, 13 figures, 1 table, 31 algorithms.

Key Result

lemma 1

Every GCDS has $t_{\mathrm{S,A,AR}}(n) \leq t_{\mathrm{A,AR}}(n) \leq t_{\mathrm{AR}}(n) \leq t(n)$.

Figures (13)

  • Figure 1: Excerpt from the example program showing long pause times in the memory-constrained setting. Both fetch_item and process_item allocate large memory blobs using a wrapper that enforces a strict limit on the total (logical) allocation size. The limit is almost reached by the end of stage 1, and only the blobs allocated in stage 2 are temporary, so nearly every iteration of the loop in stage 2 needs to make a full GC pass to collect old temporary blobs before allocating a new one for that iteration. This program is sufficient to trigger GC thrashing in Lua. Variants of this program trigger similar linear-length pause times in collectors that use generational collection and reference counting.
  • Figure 2: With and without memory pressure. The first stage is shown in blue, the second in red.
  • Figure 3: $\mathtt{GCInit}()$
  • Figure 4: $\mathtt{GCInit}()$
  • Figure 5: $\mathtt{DRInsert}(v_i \to v_j)$
  • ...and 8 more figures

Theorems & Definitions (40)

  • definition 1
  • definition 2
  • definition 3
  • definition 4
  • definition 5
  • definition 6
  • lemma 1
  • proof
  • definition 7
  • theorem 1
  • ...and 30 more