Skip to content

Commit b75a49f

Browse files
committed
GC secondary map periodically.
1 parent fd8aabf commit b75a49f

File tree

1 file changed

+22
-0
lines changed

1 file changed

+22
-0
lines changed

ruby/ext/google/protobuf_c/protobuf.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,14 +251,36 @@ void Arena_register(VALUE module) {
251251
// The object is used only for its identity; it does not contain any data.
252252
VALUE secondary_map = Qnil;
253253

254+
// Lambda that will GC entries from the secondary map that are no longer present
255+
// in the primary map.
256+
VALUE gc_secondary_map = Qnil;
257+
258+
extern VALUE weak_obj_cache;
259+
254260
static void SecondaryMap_Init() {
255261
rb_gc_register_address(&secondary_map);
262+
rb_gc_register_address(&gc_secondary_map);
256263
secondary_map = rb_hash_new();
264+
gc_secondary_map = rb_eval_string(
265+
"->(secondary, weak) {\n"
266+
" secondary.delete_if { |k, v| !weak.key?(v) }\n"
267+
"}\n");
268+
}
269+
270+
static void SecondaryMap_MaybeGC() {
271+
size_t weak_len = NUM2ULL(rb_funcall(weak_obj_cache, rb_intern("length"), 0));
272+
size_t secondary_len = RHASH_SIZE(secondary_map);
273+
size_t waste = secondary_len - weak_len;
274+
PBRUBY_ASSERT(secondary_len >= weak_len);
275+
if (waste > 1000 && waste > secondary_len * 0.2) {
276+
rb_funcall(gc_secondary_map, rb_intern("call"), 2, secondary_map, weak_obj_cache);
277+
}
257278
}
258279

259280
static VALUE SecondaryMap_Get(VALUE key) {
260281
VALUE ret = rb_hash_lookup(secondary_map, key);
261282
if (ret == Qnil) {
283+
SecondaryMap_MaybeGC();
262284
ret = rb_eval_string("Object.new");
263285
rb_hash_aset(secondary_map, key, ret);
264286
}

0 commit comments

Comments
 (0)