summaryrefslogtreecommitdiffstats
path: root/gc.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2019-02-18 01:15:23 -0800
committerKaz Kylheku <kaz@kylheku.com>2019-02-18 01:15:23 -0800
commit3931df5cba3d826511503ad1c0a5b84c1363765e (patch)
tree261bc7ec5a6f048e3e98551168ba754f80bc7523 /gc.c
parent5ceab469fc53cf29c9383f75d6208d6501256ae5 (diff)
downloadtxr-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.c12
1 files changed, 11 insertions, 1 deletions
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;