diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2019-02-18 01:15:23 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2019-02-18 01:15:23 -0800 |
commit | 3931df5cba3d826511503ad1c0a5b84c1363765e (patch) | |
tree | 261bc7ec5a6f048e3e98551168ba754f80bc7523 /gc.c | |
parent | 5ceab469fc53cf29c9383f75d6208d6501256ae5 (diff) | |
download | txr-3931df5cba3d826511503ad1c0a5b84c1363765e.tar.gz txr-3931df5cba3d826511503ad1c0a5b84c1363765e.tar.bz2 txr-3931df5cba3d826511503ad1c0a5b84c1363765e.zip |
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.
Diffstat (limited to 'gc.c')
-rw-r--r-- | gc.c | 12 |
1 files changed, 11 insertions, 1 deletions
@@ -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; |