123456789_123456789_123456789_123456789_123456789_

Module: GC

Relationships & Source Files
Defined in: gc.rb,
gc.c

Overview

The GC module provides an interface to Ruby's mark-and-sweep garbage collection mechanism.

Some of the underlying methods are also available via the ::ObjectSpace module.

You may obtain information about the operation of the GC through GC::Profiler.

Class Attribute Summary

Class Method Summary

Instance Method Summary

Class Attribute Details

.measure_total_time ⇒ Boolean (rw)

Returns the setting for GC total time measurement in the current Ractor; the main Ractor's initial setting is true and, with the default GC, other Ractors inherit their creator's setting. See .total_time.

[ GitHub ]

  
# File 'gc.rb', line 661

def self.measure_total_time
  Primitive.cexpr! %{
    RBOOL(rb_gc_impl_get_measure_total_time(rb_gc_get_objspace()))
  }
end

.measure_total_time=(setting) ⇒ setting (rw)

Enables or disables GC total time measurement; returns setting. See .total_time.

When argument object is nil or false, disables total time measurement; .measure_total_time then returns false:

GC.measure_total_time = nil   # => nil
GC.measure_total_time         # => false
GC.measure_total_time = false # => false
GC.measure_total_time         # => false

Otherwise, enables total time measurement; .measure_total_time then returns true:

GC.measure_total_time = true # => true
GC.measure_total_time        # => true
GC.measure_total_time = :foo # => :foo
GC.measure_total_time        # => true

Note that when enabled, total time measurement affects performance.

The setting is per-Ractor: it affects only the ::Ractor that sets it. With the default GC, a ::Ractor created by Ractor.new inherits the setting of the ::Ractor that creates it; the main ::Ractor starts with measurement enabled.

[ GitHub ]

  
# File 'gc.rb', line 647

def self.measure_total_time=(flag)
  Primitive.cstmt! %{
    rb_gc_impl_set_measure_total_time(rb_gc_get_objspace(), flag);
    return flag;
  }
end

.stress ⇒ setting (rw)

Returns the current GC stress-mode setting, which initially is false.

The stress mode may be set by method .stress=.

[ GitHub ]

  
# File 'gc.rb', line 109

def self.stress
  Primitive.gc_stress_get
end

.stress=(value) ⇒ value (rw)

Enables or disables stress mode. Stress mode causes GC to be invoked at every GC opportunity (all memory and object allocations); it is intended only for debugging and severely degrades performance.

Sets the current GC stress mode to the given value:

  • If the value is nil or false, disables stress mode.
  • If the value is an integer, enables stress mode with certain flags; see below.
  • Otherwise, enables stress mode without any flags.

The flags are bits in the given integer:

  • 0x01: no major GC.
  • 0x02: no immediate sweep.
  • 0x04: full mark after malloc/calloc/realloc.
[ GitHub ]

  
# File 'gc.rb', line 134

def self.stress=(flag)
  Primitive.gc_stress_set_m flag
end

Class Method Details

.config ⇒ Hash .config(hash_to_merge) ⇒ Hash

This method is implementation-specific to CRuby.

Sets or gets information about the current GC configuration.

Configuration parameters are GC implementation-specific and may change without notice.

With no argument given, returns a hash containing the configuration:

GC.config
# => {rgengc_allow_full_mark: true, implementation: "default"}

With argument hash_to_merge given, merges that hash into the stored configuration hash; ignores unknown hash keys; returns the configuration hash:

GC.config(rgengc_allow_full_mark: false)
# => {rgengc_allow_full_mark: false, implementation: "default"}
GC.config(foo: 'bar')
# => {rgengc_allow_full_mark: false, implementation: "default"}

All-Implementations Configuration

The single read-only entry for all implementations is:

  • :implementation: the string name of the implementation; for the Ruby default implementation, 'default'.

Implementation-Specific Configuration

A GC implementation maintains its own implementation-specific configuration.

For Ruby's default implementation the single entry is:

  • :rgengc_allow_full_mark: Controls whether the GC is allowed to run a full mark (young & old objects):

  • true (default): GC interleaves major and minor collections. A flag is set to notify GC that a full mark has been requested. This flag is accessible via GC.latest_gc_info(:need_major_by).

  • false: GC does not initiate a full marking cycle unless explicitly directed by user code; see GC.start. Setting this parameter to false disables young-to-old promotion. For performance reasons, we recommended warming up the application using Process.warmup before setting this parameter to false.

[ GitHub ]

  
# File 'gc.rb', line 550

def self.config hash = nil
  if Primitive.cexpr!("RBOOL(RB_TYPE_P(hash, T_HASH))")
    if hash.include?(:implementation)
      raise ArgumentError, 'Attempting to set read-only key "Implementation"'
    end

    Primitive.gc_config_set hash
  elsif hash != nil
    raise ArgumentError
  end

  Primitive.gc_config_get
end

.count ⇒ Integer

Returns the total number of times garbage collection has occurred:

With the default GC, counts the collections of the current Ractor's heap, including global collections that other Ractors started.

GC.count # => 385
GC.start
GC.count # => 386
[ GitHub ]

  
# File 'gc.rb', line 150

def self.count
  Primitive.gc_count
end

.disable ⇒ Boolean

Disables garbage collection (but .start remains potent): returns whether garbage collection was already disabled.

GC.enable
GC.disable # => false
GC.disable # => true
[ GitHub ]

  
# File 'gc.rb', line 98

def self.disable
  Primitive.gc_disable
end

.enable ⇒ Boolean

Enables garbage collection; returns whether garbage collection was disabled:

GC.disable
GC.enable # => true
GC.enable # => false
[ GitHub ]

  
# File 'gc.rb', line 84

def self.enable
  Primitive.gc_enable
end

.latest_gc_info ⇒ Hash .latest_gc_info(key) ⇒ value .latest_gc_info(hash) ⇒ Hash

With no argument given, returns information about the most recent garbage collection:

GC.latest_gc_info
# =>
{major_by: :force,
need_major_by: nil,
gc_by: :method,
have_finalizer: false,
immediate_sweep: true,
state: :none,
weak_references_count: 0,
retained_weak_references_count: 0}

With symbol argument key given, returns the value for that key:

GC.latest_gc_info(:gc_by) # => :newobj

With hash argument hash given, returns that hash with GC information merged into its content; this form may be useful in minimizing probe effects:

h = {foo: 0, bar: 1}
GC.latest_gc_info(h)
# =>
{foo: 0,
bar: 1,
major_by: nil,
need_major_by: nil,
gc_by: :newobj,
have_finalizer: false,
immediate_sweep: false,
state: :sweeping,
weak_references_count: 0,
retained_weak_references_count: 0}
[ GitHub ]

  
# File 'gc.rb', line 606

def self.latest_gc_info hash_or_key = nil
  if hash_or_key == nil
    hash_or_key = {}
  elsif Primitive.cexpr!("RBOOL(!SYMBOL_P(hash_or_key) && !RB_TYPE_P(hash_or_key, T_HASH))")
    raise TypeError, "non-hash or symbol given"
  end

  Primitive.cstmt! %{
    return rb_gc_latest_gc_info(hash_or_key);
  }
end

.start(full_mark: true, immediate_mark: true, immediate_sweep: true, global: true)

Initiates garbage collection, even if explicitly disabled by .disable.

Keyword arguments:

  • full_mark: a boolean value specifying whether to perform a major garbage collection cycle:

  • true: initiates a major garbage collection cycle, meaning all objects (old and new) are marked. When another Ractor's object space exists (a live Ractor, or a terminated one not yet absorbed), or one was absorbed since the last global collection, and global is true (the default), the cycle is a global collection instead; see global.

  • false: initiates a minor garbage collection cycle, meaning only young objects are marked.

  • immediate_mark: a boolean value specifying whether marking is performed incrementally:

  • true: marking is completed before the method returns.

  • false: marking is performed in parts, interleaved with program execution both before the method returns and afterward; therefore marking may not be completed before the return. Note that if full_mark is false, marking is always immediate, regardless of the value of immediate_mark.

  • immediate_sweep: a boolean value specifying whether sweeping is deferred (lazy sweep):

  • true: sweeping is completed before the method returns.

  • false: sweeping is performed in parts, interleaved with program execution both before the method returns and afterward; therefore sweeping may not be completed before the return.

  • global: a boolean value specifying, when another Ractor's object space exists, whether to collect every Ractor's heap together in a single stop-the-world mark/sweep cycle:

  • true: with another Ractor's object space present (see full_mark) it runs a stop-the-world cycle and reclaims shareable and cross-Ractor garbage. This option, although it defaults to true, is ignored unless full_mark, immediate_mark and immediate_sweep are all true. With a single object space it has no effect and the other options apply as usual. This option is also ignored unless you're using the default GC.

  • false: collect only the calling Ractor's own objects. Shareable objects and cross-ractor garbage are not swept.

GC.stat counts a local major collection under :major_gc_count and a local minor collection under :minor_gc_count. A global collection counts under :global_gc_count in every Ractor whose heap it collects, and under :global_gc_invocation_count in the calling Ractor.

Note that these keyword arguments are implementation- and version-dependent, are not guaranteed to be future-compatible, and may be ignored in some implementations.

[ GitHub ]

  
# File 'gc.rb', line 65

def self.start full_mark: true, immediate_mark: true, immediate_sweep: true, global: true
  Primitive.gc_start_internal full_mark, immediate_mark, immediate_sweep, false, global
end

.stat(process: false) ⇒ Hash .stat(key, process: false) ⇒ value .stat(hash, process: false) ⇒ Hash

This method is implementation-specific to CRuby.

Returns GC statistics. The particular statistics are implementation-specific and may change in the future without notice.

With process: false (the default) or nil, returns statistics for the current Ractor's object space. With any other value of process, returns process-wide statistics; see "Process statistics" below.

With no positional argument or nil given, returns a hash containing the GC statistics:

GC.stat
# =>
{count: 1,
time: 0,
marking_time: 0,
sweeping_time: 0,
total_malloc_bytes: 10432791,
total_free_bytes: 6989873,
heap_allocated_pages: 41,
heap_empty_pages: 0,
heap_allocatable_bytes: 228656,
heap_eden_pages: 41,
total_allocated_pages: 41,
total_freed_pages: 0,
malloc_increase_bytes: 0,
malloc_increase_bytes_limit: 16777216,
minor_gc_count: 0,
major_gc_count: 1,
global_gc_count: 0,
global_gc_invocation_count: 0,
compact_count: 0,
read_barrier_faults: 0,
total_moved_objects: 0,
remembered_wb_unprotected_objects: 0,
remembered_wb_unprotected_objects_limit: 7,
old_objects: 721,
old_objects_limit: 1442,
oldmalloc_increase_bytes: 0,
oldmalloc_increase_bytes_limit: 16777216,
total_allocated_objects: 36735,
total_freed_objects: 19527,
heap_available_slots: 40591,
heap_live_slots: 17208,
heap_free_slots: 23383,
heap_final_slots: 0,
heap_marked_slots: 17175}

With symbol argument key given, returns the value for that key:

GC.stat(:count) # => 30

With hash argument hash given, returns that hash with GC statistics merged into its content; this form may be useful in minimizing probe effects:

h = {foo: 0, bar: 1}
GC.stat(h)
h.keys.take(5) # => [:foo, :bar, :count, :time, :marking_time]

The hash includes entries such as:

  • :count: The total number of garbage collections of this Ractor's heap since the object space was created. It includes minor, major, and global garbage collections, and equals :minor_gc_count plus :major_gc_count plus :global_gc_count.
  • :time: The total time spent in garbage collections (in milliseconds).
  • :marking_time: The total time spent marking objects (in milliseconds).
  • :sweeping_time: The total time spent sweeping objects (in milliseconds).
  • :total_malloc_bytes: The total number of bytes allocated by malloc since application start.
  • :total_free_bytes: The total number of bytes freed since application start.
  • :heap_allocated_pages: The total number of allocated pages.
  • :heap_empty_pages: The number of pages with no live objects, and that could be released to the system.
  • :heap_allocatable_bytes: The number of bytes that can be allocated without triggering a new garbage collection cycle.
  • :heap_eden_pages: The total number of pages which contain at least one live slot.
  • :total_allocated_pages: The cumulative number of pages allocated since application start.
  • :total_freed_pages: The cumulative number of pages freed since application start.
  • :malloc_increase_bytes: Amount of memory allocated on the heap for objects. Decreased by any GC.
  • :malloc_increase_bytes_limit: When :malloc_increase_bytes crosses this limit, GC is triggered.
  • :minor_gc_count: The total number of local minor garbage collections of this Ractor's heap.
  • :major_gc_count: The total number of local major garbage collections of this Ractor's heap. Global garbage collections are counted separately.
  • :global_gc_count: The number of global (stop-the-world) garbage collections that collected this Ractor's heap. Any Ractor can start them.
  • :global_gc_invocation_count: The number of global garbage collections that this Ractor started. Each global garbage collection has exactly one starter.
  • :compact_count: The total number of compactions run since process start.
  • :read_barrier_faults: The total number of times the read barrier was triggered during compaction.
  • :total_moved_objects: The total number of objects compaction has moved.
  • :remembered_wb_unprotected_objects: The total number of objects without write barriers.
  • :remembered_wb_unprotected_objects_limit: When :remembered_wb_unprotected_objects crosses this limit, major GC is triggered.
  • :old_objects: Number of live, old objects which have survived at least 3 garbage collections.
  • :old_objects_limit: When :old_objects crosses this limit, major GC is triggered.
  • :oldmalloc_increase_bytes: Amount of memory allocated on the heap for objects. Decreased by major GC.
  • :oldmalloc_increase_bytes_limit: When :oldmalloc_increase_bytes crosses this limit, major GC is triggered.
  • :total_allocated_objects: The cumulative number of objects allocated since application start.
  • :total_freed_objects: The cumulative number of objects freed since application start.
  • :heap_available_slots: The total number of slots in all :heap_allocated_pages.
  • :heap_live_slots: The total number of slots which contain live objects.
  • :heap_free_slots: The total number of slots which do not contain live objects.
  • :heap_final_slots: The total number of slots with pending finalizers to be run.
  • :heap_marked_slots: The number of objects in this Ractor's heap marked in the last GC of that heap.

Process statistics

With process: true, the default collector reports cumulative collection counts and measured CPU time across all Ractors, retaining history from destroyed object spaces, and the state of the page pool that all object spaces share:

GC.stat(process: true)
# => {count: 42, time: 3, marking_time: 2, sweeping_time: 1,
#     minor_gc_count: 32, major_gc_count: 8, global_gc_count: 2,
#     page_pool_arenas: 2, page_pool_arenas_freed: 0,
#     page_pool_total_pages: 64, page_pool_discarded_pages: 0}

:count is the number of garbage collections in the process. Each local and each global collection counts once, so :count equals :minor_gc_count plus :major_gc_count plus :global_gc_count. It is not the sum of the ::Ractor :count values, because one global collection collects every heap.

:global_gc_count is the number of global collections in the process, however many Ractors each one stops.

The page pool keys are:

  • :page_pool_arenas: The number of page-pool arenas that are mapped now.
  • :page_pool_arenas_freed: The number of arenas that the page pool has unmapped.
  • :page_pool_total_pages: The number of page bodies in the mapped arenas.
  • :page_pool_discarded_pages: The number of free page bodies whose memory the page pool has returned to the operating system.

:time may exceed :marking_time plus :sweeping_time by one millisecond because raw nanoseconds are summed before conversion. Times measure collector CPU work, not wall-clock pauses.

Reads combine object-space publications without requesting a stop-the-world barrier. .measure_total_time controls future timing accumulation. Profiler controls do not affect these totals. A forked child inherits its parent's totals. MMTk and wbcheck raise ::NotImplementedError for process statistics.

Unavailable keys raise ::ArgumentError.

[ GitHub ]

  
# File 'gc.rb', line 347

def self.stat hash_or_key = nil, process: false
  Primitive.gc_stat hash_or_key, process
end

.stat_heap ⇒ Hash .stat_heap(heap_id) ⇒ Hash .stat_heap(heap_id, key) ⇒ value .stat_heap(nil, hash) ⇒ Hash .stat_heap(heap_id, hash) ⇒ Hash

This method is implementation-specific to CRuby.

Returns statistics for GC heaps. The particular statistics are implementation-specific and may change in the future without notice.

With no argument given, returns statistics for all heaps:

GC.stat_heap
# =>
{0 =>
{slot_size: 32,
 heap_eden_pages: 24,
 heap_eden_slots: 12288,
 total_allocated_pages: 24,
 force_major_gc_count: 0,
 force_incremental_marking_finish_count: 0,
 total_allocated_objects: 8450,
 total_freed_objects: 3120},
1 =>
{slot_size: 64,
 heap_eden_pages: 246,
 heap_eden_slots: 402802,
 total_allocated_pages: 246,
 force_major_gc_count: 2,
 force_incremental_marking_finish_count: 1,
 total_allocated_objects: 33867152,
 total_freed_objects: 33520523},
2 =>
{slot_size: 128,
 heap_eden_pages: 84,
 heap_eden_slots: 68746,
 total_allocated_pages: 84,
 force_major_gc_count: 1,
 force_incremental_marking_finish_count: 4,
 total_allocated_objects: 147491,
 total_freed_objects: 90699},
3 =>
{slot_size: 256,
 heap_eden_pages: 157,
 heap_eden_slots: 64182,
 total_allocated_pages: 157,
 force_major_gc_count: 0,
 force_incremental_marking_finish_count: 0,
 total_allocated_objects: 211460,
 total_freed_objects: 190075},
4 =>
{slot_size: 512,
 heap_eden_pages: 8,
 heap_eden_slots: 1631,
 total_allocated_pages: 8,
 force_major_gc_count: 0,
 force_incremental_marking_finish_count: 0,
 total_allocated_objects: 1422,
 total_freed_objects: 700},
5 =>
{slot_size: 1024,
 heap_eden_pages: 16,
 heap_eden_slots: 1628,
 total_allocated_pages: 16,
 force_major_gc_count: 0,
 force_incremental_marking_finish_count: 0,
 total_allocated_objects: 1230,
 total_freed_objects: 309}}

In the example above, the keys in the outer hash are the heap identifiers:

GC.stat_heap.keys # => [0, 1, 2, 3, 4, 5]

On CRuby, each heap identifier is an integer; on other implementations, a heap identifier may be a string.

With only argument heap_id given, returns statistics for the given heap identifier:

GC.stat_heap(3)
# =>
{slot_size: 256,
heap_eden_pages: 157,
heap_eden_slots: 64182,
total_allocated_pages: 157,
force_major_gc_count: 0,
force_incremental_marking_finish_count: 0,
total_allocated_objects: 225018,
total_freed_objects: 206647}

With arguments heap_id and key given, returns the value for the given key in the given heap:

GC.stat_heap(3, :slot_size) # => 256

With arguments nil and hash given, merges the statistics for all heaps into the given hash:

h = {foo: 0, bar: 1}
GC.stat_heap(nil, h).keys # => [:foo, :bar, 0, 1, 2, 3, 4]

With arguments heap_id and hash given, merges the statistics for the given heap into the given hash:

h = {foo: 0, bar: 1}
GC.stat_heap(2, h).keys
# =>
[:foo,
:bar,
:slot_size,
:heap_eden_pages,
:heap_eden_slots,
:total_allocated_pages,
:force_major_gc_count,
:force_incremental_marking_finish_count,
:total_allocated_objects,
:total_freed_objects]

The statistics for a heap may include:

  • :slot_size: The slot size of the heap in bytes.
  • :heap_allocatable_pages: The number of pages that can be allocated without triggering a new garbage collection cycle.
  • :heap_eden_pages: The number of pages in the eden heap.
  • :heap_eden_slots: The total number of slots in all of the pages in the eden heap.
  • :total_allocated_pages: The total number of pages that have been allocated in the heap.
  • :total_freed_pages: The total number of pages that have been freed and released back to the system in the heap.
  • :force_major_gc_count: The number of times this heap has forced major garbage collection cycles to start due to running out of free slots.
  • :force_incremental_marking_finish_count: The number of times this heap has forced incremental marking to complete due to running out of pooled slots.
[ GitHub ]

  
# File 'gc.rb', line 495

def self.stat_heap heap_name = nil, hash_or_key = nil
  Primitive.gc_stat_heap heap_name, hash_or_key
end

.total_time ⇒ Integer

Returns the GC total time in nanoseconds:

With the default collector, this is the current Ractor's measured GC CPU work, not wall-clock pause time.

GC.total_time # => 156250

Note that total time accumulates only when total time measurement is enabled (that is, when .measure_total_time is true):

GC.measure_total_time # => true
GC.total_time # => 625000
GC.start
GC.total_time # => 937500
GC.start
GC.total_time # => 1093750

GC.measure_total_time = false
GC.total_time # => 1250000
GC.start
GC.total_time # => 1250000
GC.start
GC.total_time # => 1250000

GC.measure_total_time = true
GC.total_time # => 1250000
GC.start
GC.total_time # => 1406250
[ GitHub ]

  
# File 'gc.rb', line 700

def self.total_time
  Primitive.cexpr! %{
    ULL2NUM(rb_gc_impl_get_total_time(rb_gc_get_objspace()))
  }
end

Instance Method Details

#garbage_collect(full_mark: true, immediate_mark: true, immediate_sweep: true, global: true)

Alias of .start

[ GitHub ]

  
# File 'gc.rb', line 70

def garbage_collect full_mark: true, immediate_mark: true, immediate_sweep: true, global: true
  Primitive.gc_start_internal full_mark, immediate_mark, immediate_sweep, false, global
end