Project

General

Profile

Actions

Feature #20612

open

Introduce new Epsilon (no-op) GC

Added by eightbitraptor (Matt V-H) 6 months ago. Updated 5 months ago.

Status:
Open
Assignee:
-
Target version:
-
[ruby-core:118481]

Description

Summary

[Github PR 11122]

This ticket proposes the introduction of a new GC, modelled on the Epsilon collector introduced in Java 11. This collector is an allocation only collector (ie. GC is a no-op), and is intended solely for testing and experimentation purposes.

Background

This ticket follows up the work in https://bugs.ruby-lang.org/issues/20470 to extract the GC into a GC interface (gc.c) and a seperate implementation (gc_impl.c).

In order to test the extraction against it's stated goals of being able to load a new GC at runtime we need a "second system" GC implementation to continue testing and developing the interface.

Epsilon GC is one of the simplest implementations of a GC that can be used for testing purposes, as it implements the correct interface needed to run Ruby code, but does no collection.

Design

It's modelled on the Epsilon collector introduced in JDK 11: A No-Op collector that implements memory allocation but no memory reclamation. Memory will continue to be allocated until the process exhausts all available memory and is shut down by the OS's OOM killer. This has the lowest possible GC latency, at the expense of memory footprint and throughput.

This collector was built by initially copying the existing GC in it's entirety and stripping out the collection related concerns. For this reason it uses the same heap/page/slot allocation strategy as Ruby's existing GC.

This choice was made for a few reasons:

  • Memory throughput: Traditionally and Epsilon collector would malloc every allocation, this GC uses an already established Ruby allocation implementation to reduce the number of malloc/free calls during allocation, allowing allocation to be faster.
  • Familiarity: Developers of the Ruby GC are already familiar with how allocation works in Ruby, this GC should remain simple to work on.
  • Simplicity: Using the existing allocation strategy allowed us to develop this quickly, and avoid having to deal with alignment issues, or abstraction leakage issues over the API.

Usage

The epsilon collection can be built as a shared library as follows:

Mac:

clang -I../src/include -I. -I../src -I.ext/include/arm64-darwin23 -Wall -undefined dynamic_lookup -g -O0 -dynamiclib -o gc/epsilon.dylib ../src/gc/epsilon.c

Linux:

gcc -O0 -g -I. -I../src/  -I../src/include -I./.ext/include/x86_64-linux/ -Wall -fPIC -shared -lc ../src/gc/epsilon.c -o gc/epsilon.so

Ruby must be built with shared GC support, and the correct library directory set in the configure path.

./configure --with-shared-gc=$(pwd)/gc

Then, the EpsilonGC can be loaded at runtime using the RUBY_GC_LIBRARY environment variable

RUBY_GC_LIBRARY=epsilon.dylib ./ruby test.rb

Evaluation

No benchmarking has been done on this code. This is intended for testing only. We verify that the EpsilonGC builds against the current version of the Ruby GC interface in Github Actions.

Actions

Also available in: Atom PDF

Like1
Like0Like0Like0Like0Like0