模块 GC

GC 模块提供了对 Ruby 标记和清除垃圾回收机制的接口。

一些底层方法也可以通过 ObjectSpace 模块使用。

您可以通过 GC::Profiler 获取有关 GC 操作的信息。

常量

INTERNAL_CONSTANTS

垃圾回收器中的内部常量。

OPTS

GC 构建选项

公共类方法

add_stress_to_class(class[, ...]) 点击切换源代码

在分配给定类的实例时引发 NoMemoryError

static VALUE
rb_gcdebug_add_stress_to_class(int argc, VALUE *argv, VALUE self)
{
    rb_objspace_t *objspace = &rb_objspace;

    if (!stress_to_class) {
        set_stress_to_class(rb_ary_hidden_new(argc));
    }
    rb_ary_cat(stress_to_class, argv, argc);
    return self;
}
auto_compact → true 或 false 点击切换源代码

返回是否已启用自动压缩。

static VALUE
gc_get_auto_compact(VALUE _)
{
    return RBOOL(ruby_enable_autocompact);
}
auto_compact = flag 点击切换源代码

更新自动压缩模式。

启用后,压缩器将在每次主要收集时执行。

启用压缩会降低主要收集的性能。

static VALUE
gc_set_auto_compact(VALUE _, VALUE v)
{
    GC_ASSERT(GC_COMPACTION_SUPPORTED);

    ruby_enable_autocompact = RTEST(v);

#if RGENGC_CHECK_MODE
    ruby_autocompact_compare_func = NULL;

    if (SYMBOL_P(v)) {
        ID id = RB_SYM2ID(v);
        if (id == rb_intern("empty")) {
            ruby_autocompact_compare_func = compare_free_slots;
        }
    }
#endif

    return v;
}
compact 点击切换源代码

此函数将 Ruby 堆中的对象压缩在一起。它通过将对象移动到未使用的空间来消除堆中的未使用空间(或碎片)。此函数返回一个哈希,其中包含有关哪些对象被移动的统计信息。有关压缩统计信息的详细信息,请参见 GC.latest_gc_info

此方法是特定于实现的,预计不会在除 MRI 之外的任何实现中实现。

要测试是否支持 GC 压缩,请使用以下习惯用法

GC.respond_to?(:compact)
static VALUE
gc_compact(VALUE self)
{
    /* Run GC with compaction enabled */
    gc_start_internal(NULL, self, Qtrue, Qtrue, Qtrue, Qtrue);

    return gc_compact_stats(self);
}
count → Integer click to toggle source

GC 发生的次数。

它返回自进程启动以来 GC 发生的次数。

# File ruby_3_3_0/gc.rb, line 105
def self.count
  Primitive.gc_count
end
disable → true or false click to toggle source

禁用垃圾回收,如果垃圾回收已禁用,则返回 true

GC.disable   #=> false
GC.disable   #=> true
# File ruby_3_3_0/gc.rb, line 69
def self.disable
  Primitive.gc_disable
end
enable → true or false click to toggle source

启用垃圾回收,如果垃圾回收以前已禁用,则返回 true

GC.disable   #=> false
GC.enable    #=> true
GC.enable    #=> false
# File ruby_3_3_0/gc.rb, line 57
def self.enable
  Primitive.gc_enable
end
latest_compact_info → hash click to toggle source

返回有关最近一次 GC 压缩中移动的对象的信息。

返回的哈希有两个键:considered 和 moved。:considered 的哈希列出了压缩器考虑移动的对象数量,:moved 哈希列出了实际移动的对象数量。某些对象无法移动(可能已固定),因此可以使用这些数字来计算压缩效率。

static VALUE
gc_compact_stats(VALUE self)
{
    size_t i;
    rb_objspace_t *objspace = &rb_objspace;
    VALUE h = rb_hash_new();
    VALUE considered = rb_hash_new();
    VALUE moved = rb_hash_new();
    VALUE moved_up = rb_hash_new();
    VALUE moved_down = rb_hash_new();

    for (i=0; i<T_MASK; i++) {
        if (objspace->rcompactor.considered_count_table[i]) {
            rb_hash_aset(considered, type_sym(i), SIZET2NUM(objspace->rcompactor.considered_count_table[i]));
        }

        if (objspace->rcompactor.moved_count_table[i]) {
            rb_hash_aset(moved, type_sym(i), SIZET2NUM(objspace->rcompactor.moved_count_table[i]));
        }

        if (objspace->rcompactor.moved_up_count_table[i]) {
            rb_hash_aset(moved_up, type_sym(i), SIZET2NUM(objspace->rcompactor.moved_up_count_table[i]));
        }

        if (objspace->rcompactor.moved_down_count_table[i]) {
            rb_hash_aset(moved_down, type_sym(i), SIZET2NUM(objspace->rcompactor.moved_down_count_table[i]));
        }
    }

    rb_hash_aset(h, ID2SYM(rb_intern("considered")), considered);
    rb_hash_aset(h, ID2SYM(rb_intern("moved")), moved);
    rb_hash_aset(h, ID2SYM(rb_intern("moved_up")), moved_up);
    rb_hash_aset(h, ID2SYM(rb_intern("moved_down")), moved_down);

    return h;
}
latest_gc_info → hash click to toggle source
latest_gc_info(hash) → hash
latest_gc_info(:major_by) → :malloc

返回有关最近一次垃圾回收的信息。

如果给出了可选参数 hash,则会覆盖它并返回它。这是为了避免探测效应。

# File ruby_3_3_0/gc.rb, line 266
def self.latest_gc_info hash_or_key = nil
  Primitive.gc_latest_gc_info hash_or_key
end
malloc_allocated_size → Integer click to toggle source

返回 malloc() 分配的内存大小。

仅在使用 CALC_EXACT_MALLOC_SIZE 构建 ruby 时可用。

static VALUE
gc_malloc_allocated_size(VALUE self)
{
    return UINT2NUM(rb_objspace.malloc_params.allocated_size);
}
malloc_allocations → Integer click to toggle source

返回 malloc() 分配的数量。

仅在使用 CALC_EXACT_MALLOC_SIZE 构建 ruby 时可用。

static VALUE
gc_malloc_allocations(VALUE self)
{
    return UINT2NUM(rb_objspace.malloc_params.allocations);
}
measure_total_time → true/false 点击切换源代码

返回 measure_total_time 标志(默认:true)。请注意,测量可能会影响应用程序性能。

# File ruby_3_3_0/gc.rb, line 308
def self.measure_total_time
  Primitive.cexpr! %{
    RBOOL(rb_objspace.flags.measure_gc)
  }
end
measure_total_time = true/false 点击切换源代码

启用测量 GC 时间。您可以使用 GC.stat(:time) 获取结果。请注意,GC 时间测量可能会导致一些性能开销。

# File ruby_3_3_0/gc.rb, line 296
def self.measure_total_time=(flag)
  Primitive.cstmt! %{
    rb_objspace.flags.measure_gc = RTEST(flag) ? TRUE : FALSE;
    return flag;
  }
end
remove_stress_to_class(class[, ...]) 点击切换源代码

在分配给定类的实例时不再引发 NoMemoryError

static VALUE
rb_gcdebug_remove_stress_to_class(int argc, VALUE *argv, VALUE self)
{
    rb_objspace_t *objspace = &rb_objspace;
    int i;

    if (stress_to_class) {
        for (i = 0; i < argc; ++i) {
            rb_ary_delete_same(stress_to_class, argv[i]);
        }
        if (RARRAY_LEN(stress_to_class) == 0) {
            set_stress_to_class(0);
        }
    }
    return Qnil;
}
start(full_mark: true, immediate_mark: true, immediate_sweep: true) 点击切换源代码

启动垃圾回收,即使手动禁用。

full_mark 关键字参数决定是否执行主要垃圾回收周期。当设置为 true 时,将运行主要垃圾回收周期,这意味着所有对象都将被标记。当设置为 false 时,将运行次要垃圾回收周期,这意味着只有年轻对象会被标记。

immediate_mark 关键字参数决定是否执行增量标记。当设置为 true 时,标记将在调用此方法期间完成。当设置为 false 时,标记将分步执行,与未来的 Ruby 代码执行交织在一起,因此标记可能不会在此方法调用期间完成。请注意,如果 full_markfalse,则无论 immediate_mark 的值如何,标记始终是立即执行的。

immedate_sweep 关键字参数决定是否延迟清除(使用延迟清除)。当设置为 true 时,清除将分步执行,与未来的 Ruby 代码执行交织在一起,因此清除可能不会在此方法调用期间完成。当设置为 false 时,清除将在调用此方法期间完成。

注意:这些关键字参数依赖于实现和版本。它们不保证与未来兼容,如果底层实现不支持它们,可能会被忽略。

# File ruby_3_3_0/gc.rb, line 38
def self.start full_mark: true, immediate_mark: true, immediate_sweep: true
  Primitive.gc_start_internal full_mark, immediate_mark, immediate_sweep, false
end
stat → Hash 点击切换源代码
stat(hash) → Hash
stat(:key) → 数值

返回一个包含有关 GC 信息的 Hash

哈希的内容是特定于实现的,将来可能会在未经通知的情况下更改。

哈希包含有关 GC 内部统计信息的信息,例如

count

自应用程序启动以来运行的垃圾回收总次数(计数包括次要和主要垃圾回收)

time

垃圾回收总共花费的时间(以毫秒为单位)

heap_allocated_pages

:heap_eden_pages + :heap_tomb_pages 的总数

heap_sorted_length

可以容纳所有页面引用缓冲区的页面数

heap_allocatable_pages

应用程序在没有额外 GC 的情况下可以分配的页面总数

heap_available_slots

所有 :heap_allocated_pages 中的插槽总数

heap_live_slots

包含活动对象的插槽总数

heap_free_slots

不包含活动对象的插槽总数

heap_final_slots

待运行的终结器插槽总数

heap_marked_slots

上次 GC 中标记的对象总数

heap_eden_pages

至少包含一个活动插槽的页面总数

heap_tomb_pages

不包含任何活动插槽的页面总数

total_allocated_pages

自应用程序启动以来分配的页面累计数

total_freed_pages

自应用程序启动以来释放的页面累计数

total_allocated_objects

自应用程序启动以来分配的对象累计数

total_freed_objects

自应用程序启动以来释放的对象累计数

malloc_increase_bytes

为对象在堆上分配的内存量。通过任何 GC 减少

malloc_increase_bytes_limit

:malloc_increase_bytes 超过此限制时,将触发 GC

minor_gc_count

自进程启动以来运行的次要垃圾回收总次数

major_gc_count

自进程启动以来运行的主要垃圾回收总次数

compact_count

自进程启动以来运行的压缩总次数

read_barrier_faults

压缩期间读取屏障触发的总次数

total_moved_objects

压缩移动的对象总数

remembered_wb_unprotected_objects

没有写屏障的对象总数

remembered_wb_unprotected_objects_limit

:remembered_wb_unprotected_objects超过此限制时,将触发主GC

old_objects

至少经历过3次垃圾回收的存活老对象的数量

old_objects_limit

:old_objects超过此限制时,将触发主GC

oldmalloc_increase_bytes

为对象在堆上分配的内存量。通过主GC减少

oldmalloc_increase_bytes_limit

:old_malloc_increase_bytes超过此限制时,将触发主GC

如果给出了可选参数 hash,则会覆盖它并返回它。这是为了避免探测效应。

此方法仅适用于CRuby。

# File ruby_3_3_0/gc.rb, line 189
def self.stat hash_or_key = nil
  Primitive.gc_stat hash_or_key
end
stat_heap → Hash 点击切换源代码
stat_heap(nil, hash) → Hash
stat_heap(heap_name) → Hash
stat_heap(heap_name, hash) → Hash
stat_heap(heap_name, :key) → Numeric

返回GC中堆的信息。

如果第一个可选参数heap_name被传入且不为nil,则返回一个包含有关特定堆信息的Hash。否则,它将返回一个Hash,其中堆名称作为键,包含有关堆信息的Hash作为值。

如果第二个可选参数hash_or_key被作为Hash给出,它将被覆盖并返回。这是为了避免探测效应。

如果两个可选参数都被传入,并且第二个可选参数是一个符号,它将返回特定堆的值的Numeric

在CRuby中,heap_name的类型为Integer,但在其他实现中可能为String类型。

哈希的内容是特定于实现的,将来可能会在未经通知的情况下更改。

如果给出了可选参数hash,它将被覆盖并返回。

此方法仅适用于CRuby。

该哈希包含有关GC中内部信息的以下键

slot_size

堆的槽大小(以字节为单位)。

heap_allocatable_pages

可以在不触发新的垃圾回收周期的情况下分配的页面数。

heap_eden_pages

伊甸园堆中的页面数。

heap_eden_slots

伊甸园堆中所有页面中的槽总数。

heap_tomb_pages

坟墓堆中的页面数。坟墓堆只包含没有活对象的页面。

heap_tomb_slots

堆中所有页面中的插槽总数。

total_allocated_pages

堆中已分配的页面总数。

total_freed_pages

堆中已释放并释放回系统的页面总数。

force_major_gc_count

由于可用插槽不足,此堆强制启动主要垃圾回收周期的次数。

force_incremental_marking_finish_count

此堆由于可用池化插槽不足而强制完成增量标记的次数。

# File ruby_3_3_0/gc.rb, line 252
def self.stat_heap heap_name = nil, hash_or_key = nil
  Primitive.gc_stat_heap heap_name, hash_or_key
end
stress → integer, true 或 false 点击以切换源代码

返回 GC 压力模式的当前状态。

# File ruby_3_3_0/gc.rb, line 77
def self.stress
  Primitive.gc_stress_get
end
stress = flag → flag 点击以切换源代码

更新 GC 压力模式。

启用压力模式时,GC 将在每次 GC 机会调用:所有内存和对象分配。

启用压力模式会降低性能,仅用于调试。

flag 可以是 true、false 或按位或运算后的整数标志。

0x01:: no major GC
0x02:: no immediate sweep
0x04:: full mark after malloc/calloc/realloc
# File ruby_3_3_0/gc.rb, line 95
def self.stress=(flag)
  Primitive.gc_stress_set_m flag
end
total_time → int 点击以切换源代码

返回以纳秒为单位测量的 GC 总时间。

# File ruby_3_3_0/gc.rb, line 318
def self.total_time
  Primitive.cexpr! %{
    ULL2NUM(rb_objspace.profile.marking_time_ns + rb_objspace.profile.sweeping_time_ns)
  }
end
verify_compaction_references(toward: nil, double_heap: false) → hash 点击以切换源代码

验证压缩引用一致性。

此方法是特定于实现的。在压缩期间,已移动的对象将被替换为 T_MOVED 对象。压缩后,任何对象都不应引用 T_MOVED 对象。

此函数扩展堆以确保有足够的空间移动所有对象,压缩堆以确保所有对象都移动,更新所有引用,然后执行完整的 GC。如果任何对象包含对 T_MOVED 对象的引用,则该对象应被推送到标记堆栈上,并将导致 SEGV。

# File ruby_3_3_0/gc.rb, line 285
def self.verify_compaction_references(toward: nil, double_heap: false, expand_heap: false)
  Primitive.gc_verify_compaction_references(double_heap, expand_heap, toward == :empty)
end
verify_internal_consistency → nil 点击以切换源代码

验证内部一致性。

此方法是特定于实现的。现在此方法检查 RGenGC 支持的代际一致性。

static VALUE
gc_verify_internal_consistency_m(VALUE dummy)
{
    gc_verify_internal_consistency(&rb_objspace);
    return Qnil;
}

公共实例方法

garbage_collect(full_mark: true, immediate_mark: true, immediate_sweep: true) 点击以切换源代码

GC.start 的别名

# File ruby_3_3_0/gc.rb, line 43
def garbage_collect full_mark: true, immediate_mark: true, immediate_sweep: true
  Primitive.gc_start_internal full_mark, immediate_mark, immediate_sweep, false
end