From 0ed46d885dba49ac2c2628d742cbbd7b6afea9fb Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Mon, 18 Feb 2019 01:15:23 -0800 Subject: gc: bug: finalized objects not reclaimed. The problem: in an incremental GC run, when an generation 0 object is determined to be unreachable and has a registered finalizer, it ends up hanging around until a full GC. This is because it is marked as if it were reachable (just in case the finalizer re-introduces it into the object graph) and left to be processed at the next GC. However, what's missing is that the object is not in the freshobj array any more, and so it is not reclaimed by the sweep function. Effectively, it's as if the object had been promoted to gen 1. * gc.c (call_finalizers_impl): After invoking a finalizer, if the object is still in gen 0, add it to the freshobj array as if it had just been allocated. If there is no room in the freshobj array, set the full_gc flag, as usual. --- gc.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/gc.c b/gc.c index 5b1bdcd3..19032cbe 100644 --- a/gc.c +++ b/gc.c @@ -700,7 +700,17 @@ static val call_finalizers_impl(val ctx, while (found) { struct fin_reg *next = found->next; - funcall1(found->fun, found->obj); + val obj = found->obj; + funcall1(found->fun, obj); +#if CONFIG_GEN_GC + /* Note: here an object may be added to freshobj more than once, since + * multiple finalizers can be registered. + */ + if (freshobj_idx < FRESHOBJ_VEC_SIZE && obj->t.gen == 0) + freshobj[freshobj_idx++] = obj; + else + full_gc = 1; +#endif free(found); found = next; ret = t; -- cgit v1.2.3