当最后一个引用被垃圾回收时,或者当 Any 引用被垃圾回收时,是否调用终结器?
Are finalisers called when the last reference is garbage collected, or when Any reference is garbage collected?
julia docs 说:
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.
但是,我似乎观察到它们在对我的类型的第一个引用丢失其最后一个引用时触发。
考虑:
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
有 2 个引用我的 Foo(1)
,分别是 a
和 b
我本以为:
- 当
a
更改为其他内容时,没有任何反应
- 当
b
也改成别的东西,都注册了finalizers
触发器。导致 "a" 和 "b" 都被添加到 fin_calls
数组。
相反,我观察到的是:
我本以为:
- 当
a
改成别的东西时,都注册了finalizers
触发器。导致 "a" 和 "b" 都被添加到 fin_calls
数组。
- 当
b
也发生变化时,不会再发生任何事情。
理解正在发生的事情的正确方法是什么?
这是在 julia 6.0
我重现这个的能力似乎各不相同。
- 在原始机器上它显示为 0.6.0。
- 在另一台机器上:
- 0.6.1 (-O2 default )导致finaliser没有被调用的失败(没关系,finaliser晚点调用是可以的)。
- 0.7-dev (-O0) 结果通过,
- 0.7-dev(-O1 或更高版本)由于两者都被调用而导致失败。
如果不使用变量,
垃圾收集器可以在最后一次使用后的任何时间自由收集变量。
如果您根本不使用变量,那么优化器可以完全不在实际代码中生成它。
我相信这就是发生的事情。
如果我添加更多变量的使用,则行为符合预期。
using Base.Test
"This function makes use of `xs` in a way no optimizer can possibly remove"
function use(xs...)
mktemp() do fn, fh
print(fh, xs)
end
end
mutable struct Foo
val
end
function foo()
@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"))
use(a,b)
@test fin_calls == []
a = 7
gc()
use(b)
@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
这段代码,对我来说进入了最终测试,然后失败了,因为那时 fin_calls
从未被调用过。因为垃圾收集器可以选择不 运行.
结束
julia docs 说:
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.
但是,我似乎观察到它们在对我的类型的第一个引用丢失其最后一个引用时触发。
考虑:
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
有 2 个引用我的 Foo(1)
,分别是 a
和 b
我本以为:
- 当
a
更改为其他内容时,没有任何反应 - 当
b
也改成别的东西,都注册了finalizers
触发器。导致 "a" 和 "b" 都被添加到fin_calls
数组。
相反,我观察到的是:
我本以为:
- 当
a
改成别的东西时,都注册了finalizers
触发器。导致 "a" 和 "b" 都被添加到fin_calls
数组。 - 当
b
也发生变化时,不会再发生任何事情。
理解正在发生的事情的正确方法是什么? 这是在 julia 6.0
我重现这个的能力似乎各不相同。
- 在原始机器上它显示为 0.6.0。
- 在另一台机器上:
- 0.6.1 (-O2 default )导致finaliser没有被调用的失败(没关系,finaliser晚点调用是可以的)。
- 0.7-dev (-O0) 结果通过,
- 0.7-dev(-O1 或更高版本)由于两者都被调用而导致失败。
如果不使用变量, 垃圾收集器可以在最后一次使用后的任何时间自由收集变量。
如果您根本不使用变量,那么优化器可以完全不在实际代码中生成它。
我相信这就是发生的事情。 如果我添加更多变量的使用,则行为符合预期。
using Base.Test
"This function makes use of `xs` in a way no optimizer can possibly remove"
function use(xs...)
mktemp() do fn, fh
print(fh, xs)
end
end
mutable struct Foo
val
end
function foo()
@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"))
use(a,b)
@test fin_calls == []
a = 7
gc()
use(b)
@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
这段代码,对我来说进入了最终测试,然后失败了,因为那时 fin_calls
从未被调用过。因为垃圾收集器可以选择不 运行.
结束