The julia docs say:
finalizer(x, f)
Register a function f(x) to be called when there are no program-accessible references to x. The type of x must be a mutable struct, otherwise the behavior of this function is unpredictable.
However, I seem to be observing that they are triggering when the first reference to my type loses its last reference.
Consider:
using Base.Test
mutable struct Foo
val
end
@testset "how do Finalisers work" begin let
fin_calls = []
a = Foo(1)
b = a
finalizer(a, _ -> push!(fin_calls, "a"))
finalizer(b, _ -> push!(fin_calls, "b"))
@test fin_calls == []
a = 7
gc()
@test fin_calls == [] # Fails: Evaluated: Any["a", "b"] == Any[]
#shouldn't trigger finaliser as still has 1 ref, or so I thought
b=8
gc()
@test Set(fin_calls) == Set(["a", "b"]) #both finalizers should trigger
end end
There are 2 references to my Foo(1), those being a and b
I would have expected that:
- When
ais changed to something else, nothing happens - When
bis also changed so something else, both registeredfinalizerstrigger. Causing "a" and "b" both to be added to thefin_callsarray.
Instead, what I am observing is:
I would have expected that:
- When
ais changed to something else, both registeredfinalizerstrigger. Causing "a" and "b" both to be added to thefin_callsarray. - When
bis also changed so something else, nothing further occurs.
What is the correct way to understand what is going on? This is in julia 6.0
My ability to reproduce this seems varied.
- On original machine it showed for 0.6.0.
- On another machine:
- 0.6.1 (-O2 default ) resulted in a failure of the finaliser not being called (which is OK, it is ok for finaliser to be called late).
- 0.7-dev (-O0) resulted in a pass,
- 0.7-dev (-O1 or higher) resulted in Failure due to both being called.