> Two things can easily cause this not to call the finalizer as soon as
> you expect.
> 1. If no further consing occurs, no GC will occur, and hence
> finalizers will not be considered.
I should have stated that I run (sb-ext:gc :full t) after making sure
the object is no longer accessible (clearing * etc).
> 2. Even if consing occurred, a leftover pointer to FOO in register or
> on stack can cause it to be retained. (Or an apparent pointer: SBCL's
> GC is conservative on stack and registers on x86 and x86-64.)
That seems to be the case. How can I prevent this from happening on SBCL?
> I'm uncertain what the issue here is
> * Are your finalizers not firing, ever?
> * Are they firing, but not in a sufficiently predictable or timely fashion?
> ...or something else?
The finalizers only fire once the (sleep 10000) finishes sleeping
(what happens then is that probably the stack frame gets popped and
the accidental pointer discarded). If in the examples (sleep 10000) is
replaced with a computation that never terminates, the thread will
never be released even when object foo is not reachable anymore (the
fact that there's a pointer on the stack or in a register is an
implementation detail, but foo itself is no longer reachable in the
semantics of the code - that's the whole point of using weak
This is a real use case of Eager Future - foo would be a
future/promise structure, and the computation could either be
non-terminating speculative, or something that's sleeping on a
semaphore that will never be woken.
As I stated before, Clozure produces the expected results - foo is
collected, the finalizer gets called, and the non-terminating
There's no timing guarantees for when finalizers are called, but in
this case it's guaranteed that the finalizer will *never* be called in
SBCL, which IMO is a bug.
This doesn't happen in all ways that foo can be referenced. For
example, special variables do the right thing:
(defparameter dynamic-foo (make-instance 'foo))
(let ((s *standard-output*))
(let ((thread sb-thread:*current-thread*))
(format s "FINALIZING3~%")
(lambda () (throw 'done nil))))))
(setf dynamic-foo nil)
(sb-ext:gc :full t)
I can't use dynamic bindings for holding the weak pointer. Is there
another way to do it?