模块 GC
GC 模块提供了对 Ruby 标记和清除垃圾回收机制的接口。
一些底层方法也可以通过 ObjectSpace
模块使用。
您可以通过 GC::Profiler
获取有关 GC 操作的信息。
常量
- INTERNAL_CONSTANTS
垃圾回收器中的内部常量。
- OPTS
GC 构建选项
公共类方法
在分配给定类的实例时引发 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; }
返回是否已启用自动压缩。
static VALUE gc_get_auto_compact(VALUE _) { return RBOOL(ruby_enable_autocompact); }
更新自动压缩模式。
启用后,压缩器将在每次主要收集时执行。
启用压缩会降低主要收集的性能。
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; }
此函数将 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); }
GC 发生的次数。
它返回自进程启动以来 GC 发生的次数。
# File ruby_3_3_0/gc.rb, line 105 def self.count Primitive.gc_count end
禁用垃圾回收,如果垃圾回收已禁用,则返回 true
。
GC.disable #=> false GC.disable #=> true
# File ruby_3_3_0/gc.rb, line 69 def self.disable Primitive.gc_disable end
启用垃圾回收,如果垃圾回收以前已禁用,则返回 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
返回有关最近一次 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; }
返回有关最近一次垃圾回收的信息。
如果给出了可选参数 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() 分配的内存大小。
仅在使用 CALC_EXACT_MALLOC_SIZE
构建 ruby 时可用。
static VALUE gc_malloc_allocated_size(VALUE self) { return UINT2NUM(rb_objspace.malloc_params.allocated_size); }
返回 malloc() 分配的数量。
仅在使用 CALC_EXACT_MALLOC_SIZE
构建 ruby 时可用。
static VALUE gc_malloc_allocations(VALUE self) { return UINT2NUM(rb_objspace.malloc_params.allocations); }
返回 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
启用测量 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
在分配给定类的实例时不再引发 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; }
启动垃圾回收,即使手动禁用。
full_mark
关键字参数决定是否执行主要垃圾回收周期。当设置为 true
时,将运行主要垃圾回收周期,这意味着所有对象都将被标记。当设置为 false
时,将运行次要垃圾回收周期,这意味着只有年轻对象会被标记。
immediate_mark
关键字参数决定是否执行增量标记。当设置为 true
时,标记将在调用此方法期间完成。当设置为 false
时,标记将分步执行,与未来的 Ruby 代码执行交织在一起,因此标记可能不会在此方法调用期间完成。请注意,如果 full_mark
为 false
,则无论 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
返回一个包含有关 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
返回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
返回 GC 压力模式的当前状态。
# File ruby_3_3_0/gc.rb, line 77 def self.stress Primitive.gc_stress_get end
更新 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
返回以纳秒为单位测量的 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
验证压缩引用一致性。
此方法是特定于实现的。在压缩期间,已移动的对象将被替换为 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
验证内部一致性。
此方法是特定于实现的。现在此方法检查 RGenGC 支持的代际一致性。
static VALUE gc_verify_internal_consistency_m(VALUE dummy) { gc_verify_internal_consistency(&rb_objspace); return Qnil; }
公共实例方法
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