Open
Description
Scenario:
- Master creates a RemoteRef on worker 2
- RemoteRef is sent to Worker 3 as part of message, but not used/assigned/stored on 3
- Reference to RemoteRef is removed from 1 and gc() called everywhere
- Reference continues to exist on 2 since it has not received a "del msg" from 3.
julia> addprocs(2)
2-element Array{Int64,1}:
2
3
julia> # create a reference on pid 2
rr = RemoteRef(2)
RemoteRef(2,1,4)
julia> # See if anything has actually been created on worker 2
Base.remote_do(2, ()->println(keys(Base.PGRP.refs)))
From worker 2: Any[]
julia> # Nope, nothing
put!(rr, :OK)
RemoteRef(2,1,4)
julia> # Now, see again
Base.remote_do(2, ()->println(keys(Base.PGRP.refs)))
From worker 2: Any[(1,4)]
julia> # It exists.
# Let us send this reference to a 3rd worker.
Base.remote_do(3, x->nothing, rr)
julia> # Check which workers that supposed to hold references to this RemoteRef
Base.remote_do(2, ()->println(Base.PGRP.refs[(1,4)].clientset))
From worker 2: IntSet([1, 3])
julia> # 2 believes that 1 and 3 hold a reference
julia> # Clear locally and run gc()
rr=nothing
julia> @everywhere gc()
julia> @everywhere gc()
julia> @everywhere gc()
julia> # 1 is cleared, but worker 2 believes that 3 continues to hold a reference
Base.remote_do(2, ()->println(Base.PGRP.refs[(1,4)].clientset))
From worker 2: IntSet([3])
julia>
I have tracked it down to finalizers not being called on the RemoteRef. The finalizer sends a del_msg to the processes actually holding the value.
Finalizers are not being called for regular objects too, when they are serialized to a remote worker.
julia> addprocs(2)
2-element Array{Int64,1}:
2
3
julia> # creates workers with pids 2 and 3
@everywhere begin
function finalize_foo(f)
v = f.foo
@schedule println("FOO finalized $v")
end
type Foo
foo
Foo(x) = (f=new(x); finalizer(f, finalize_foo); f)
end
function Base.serialize(s::SerializationState, f::Foo)
invoke(serialize, Tuple{SerializationState, Any}, s, f)
end
function Base.deserialize(s::SerializationState, t::Type{Foo})
f = invoke(deserialize, Tuple{SerializationState, DataType}, s, t)
Foo(myid())
end
end
julia> Base.remote_do(3, x->nothing, Foo(0))
RemoteRef(3,1,6)
julia> @everywhere gc()
FOO finalized 0
julia> @everywhere gc()
julia> @everywhere gc()
As can be seen, Foo was not finalized on worker 3.
cc: @carnaval , @JeffBezanson