summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Zhu <[email protected]>2024-02-23 13:50:46 -0500
committerPeter Zhu <[email protected]>2024-02-26 09:20:05 -0500
commit83e676e5f9049168047c36d1bbd75ac342e6fed6 (patch)
treec76b9d525d3e463154f3bd9b90aad2d23318497e
parent1a57fee7af872a4efa94ba0e8f350c6ee6617f80 (diff)
Don't lookup finalizers if FL_FINALIZE flag not set
The FL_FINALIZE flag is set when there are finalizers for the object. We can improver performance by not looking up in the table if the flag is not set. Using the following C extension: #include "ruby/ruby.h" static void data_free(void *_ptr) {} static const rb_data_type_t data_type = { "my_type", { NULL, data_free, }, 0, 0, 0 }; static VALUE data_alloc(VALUE klass) { return TypedData_Wrap_Struct(klass, &data_type, (void *)1); } void Init_myext(void) { VALUE my_klass = rb_define_class("MyClass", rb_cObject); rb_define_alloc_func(my_klass, data_alloc); } And the following benchmark: require "benchmark" final_objs = 1_000_000.times.map do o = Object.new ObjectSpace.define_finalizer(o, proc {}) o end puts(Benchmark.measure do 100_000_000.times do MyClass.new end end) Before: 10.974190 0.355037 11.329227 ( 11.416772) After: 7.664310 0.347598 8.011908 ( 8.268969)
-rw-r--r--gc.c24
1 files changed, 17 insertions, 7 deletions
diff --git a/gc.c b/gc.c
index c6e0752a3e..cec6c94334 100644
--- a/gc.c
+++ b/gc.c
@@ -3143,7 +3143,7 @@ static inline void
make_zombie(rb_objspace_t *objspace, VALUE obj, void (*dfree)(void *), void *data)
{
struct RZombie *zombie = RZOMBIE(obj);
- zombie->basic.flags = T_ZOMBIE | (zombie->basic.flags & FL_SEEN_OBJ_ID);
+ zombie->basic.flags = T_ZOMBIE | (zombie->basic.flags & (FL_SEEN_OBJ_ID | FL_FINALIZE));
zombie->dfree = dfree;
zombie->data = data;
VALUE prev, next = heap_pages_deferred_final;
@@ -4115,15 +4115,22 @@ run_finalizer(rb_objspace_t *objspace, VALUE obj, VALUE table)
static void
run_final(rb_objspace_t *objspace, VALUE zombie)
{
- st_data_t key, table;
-
if (RZOMBIE(zombie)->dfree) {
RZOMBIE(zombie)->dfree(RZOMBIE(zombie)->data);
}
- key = (st_data_t)zombie;
- if (st_delete(finalizer_table, &key, &table)) {
- run_finalizer(objspace, zombie, (VALUE)table);
+ st_data_t key = (st_data_t)zombie;
+ if (FL_TEST_RAW(zombie, FL_FINALIZE)) {
+ st_data_t table;
+ if (st_delete(finalizer_table, &key, &table)) {
+ run_finalizer(objspace, zombie, (VALUE)table);
+ }
+ else {
+ rb_bug("FL_FINALIZE flag is set, but finalizers are not found");
+ }
+ }
+ else {
+ GC_ASSERT(!st_lookup(finalizer_table, key, NULL));
}
}
@@ -4299,9 +4306,12 @@ rb_objspace_call_finalizer(rb_objspace_t *objspace)
st_foreach(finalizer_table, force_chain_object, (st_data_t)&list);
while (list) {
struct force_finalize_list *curr = list;
- st_data_t obj = (st_data_t)curr->obj;
run_finalizer(objspace, curr->obj, curr->table);
+ FL_UNSET(curr->obj, FL_FINALIZE);
+
+ st_data_t obj = (st_data_t)curr->obj;
st_delete(finalizer_table, &obj, 0);
+
list = curr->next;
xfree(curr);
}