Julia 当最后一个引用被垃圾收集时,或者当任何引用被垃圾收集时,是否调用终结器?
他们说: 终结器(x,f) 注册一个函数f(x),当没有 对x的程序可访问引用。x的类型必须是可变的 结构,否则此函数的行为是不可预测的 然而,我似乎注意到,当对我的类型的第一个引用丢失最后一个引用时,它们就会触发 考虑:Julia 当最后一个引用被垃圾收集时,或者当任何引用被垃圾收集时,是否调用终结器?,julia,finalizer,Julia,Finalizer,他们说: 终结器(x,f) 注册一个函数f(x),当没有 对x的程序可访问引用。x的类型必须是可变的 结构,否则此函数的行为是不可预测的 然而,我似乎注意到,当对我的类型的第一个引用丢失最后一个引用时,它们就会触发 考虑: using Base.Test mutable struct Foo val end @testset "how do Finalisers work" begin let fin_calls = [] a = Foo(1) b = a
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
我的Foo(1)
有两个参考,分别是a
和b
我原以为:
- 当
被更改为其他内容时,不会发生任何事情a
- 当
也被更改为其他内容时,两个注册的b
终结器都会触发。导致将“a”和“b”都添加到
数组中fin\u调用
- 当
更改为其他内容时,两个注册的a
终结器都会触发。导致将“a”和“b”都添加到
数组中fin\u调用
- 当
也被更改为其他内容时,不会再发生任何变化b
- 在原机上显示为0.6.0
- 在另一台机器上:
- 0.6.1(-O2默认值)导致未调用最终用户失败(这是正常的,延迟调用最终用户也可以)
- 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\u调用
从未被调用过。因为垃圾收集器可以选择不运行
结束