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 → 整数 点击切换源代码

GC 发生的次数。

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

# File gc.rb, line 105
def self.count
  Primitive.gc_count
end
disable → true 或 false 点击切换源代码

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

GC.disable   #=> false
GC.disable   #=> true
# File gc.rb, line 69
def self.disable
  Primitive.gc_disable
end
enable → true 或 false 点击切换源代码

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

GC.disable   #=> false
GC.enable    #=> true
GC.enable    #=> false
# File gc.rb, line 57
def self.enable
  Primitive.gc_enable
end
latest_compact_info → 哈希 点击切换源代码

返回有关在最近的 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 → 哈希 点击切换源代码
latest_gc_info(哈希) → 哈希
latest_gc_info(:major_by) → :malloc

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

如果给出了可选参数哈希,则会覆盖它并返回它。这旨在避免探测效应。

# File 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 → 整数 点击切换源代码

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

仅当使用 CALC_EXACT_MALLOC_SIZE 构建 Ruby 时才可用。

static VALUE
gc_malloc_allocated_size(VALUE self)
{
    return UINT2NUM(rb_objspace.malloc_params.allocated_size);
}
malloc_allocations → 整数 点击切换源代码

返回 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 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 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 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) → Numeric

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

哈希的内容是实现特定的,并且将来可能会在不另行通知的情况下更改。

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

count

自应用程序启动以来运行的垃圾回收总数(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

如果给出了可选参数哈希,则会覆盖它并返回它。这旨在避免探测效应。

此方法仅适用于 CRuby。

# File 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_pages

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

eden 堆中的页面数。

heap_eden_slots

heap_tomb_pages

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

tomb 堆中的页面数。tomb 堆仅包含没有任何活动对象的页面。

heap_tomb_slots

total_allocated_pages

堆中已分配的页面总数。

total_freed_pages

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

force_major_gc_count

由于空闲槽用尽,此堆强制启动的主要垃圾回收周期次数。

force_incremental_marking_finish_count

由于池槽用尽,此堆强制增量标记完成的次数。

# File 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 or false 单击以切换源

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

# File gc.rb, line 77
def self.stress
  Primitive.gc_stress_get
end
stress = flag → flag 单击以切换源

更新 GC 压力模式。

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

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

标志可以是 true、false 或与以下标志进行按位 OR 的整数。

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

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

# File 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 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 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