Julia 当最后一个引用被垃圾收集时,或者当任何引用被垃圾收集时,是否调用终结器?

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

他们说:

终结器(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
    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
    也被更改为其他内容时,不会再发生任何变化
了解正在发生的事情的正确方法是什么? 这是茱莉亚6.0版

我的复制能力似乎各不相同

  • 在原机上显示为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调用
      从未被调用过。因为垃圾收集器可以选择不运行

      结束