Skip to content

Thread-local current_task keeps garbage alive #40626

@maleadt

Description

@maleadt

When returning values from tasks executed on another thread, those values are kept alive even though it should be possible to collect them:

julia> a = [2,2];
julia> finalizer(a) do _
         Core.println("finalizing a")
       end

julia> t = Threads.@spawn (println("returning a from thread $(Threads.threadid())"); a)
Task (runnable) @0x00007fffb73e8e80
returning a from thread 2

julia> dump(t)
Task
  next: Nothing nothing
  queue: Nothing nothing
  storage: Nothing nothing
  donenotify: Base.GenericCondition{Base.Threads.SpinLock}
    waitq: Base.InvasiveLinkedList{Task}
      head: Nothing nothing
      tail: Nothing nothing
    lock: Base.Threads.SpinLock
      owned: Int64 0
  result: Array{Int64}((2,)) [2, 2] #  <----------------- the array a is being kept alive by the task
  logstate: Nothing nothing
  code: #3 (function of type var"#3#4")
  _state: UInt8 0x01
  sticky: Bool false
  _isexception: Bool false

julia> wait(t)
julia> a = nothing
julia> t = nothing
julia> GC.gc(true)

# nothing is collected

Running under gdb reveals that the task object is being kept alive in the thread's local storage:

$ gdb --args julia -t2
(gdb) run

julia> code from above

(gdb) call jl_(jl_all_tls_states[1].current_task)
Task(next=nothing, queue=nothing, storage=nothing,
     donenotify=Base.GenericCondition{Base.Threads.SpinLock}(waitq=Base.InvasiveLinkedList{Task}(head=nothing, tail=nothing), lock=Base.Threads.SpinLock(owned=0)),
     result=Array{Int64, (2,)}[2, 2], # <------------------- our array again
     logstate=nothing, code=Main.var"#3", _state=0x01, sticky=false, _isexception=false)

Running another task on the same thread replaces that sate and allows collection of the array:

julia> # code from above

julia> t = Threads.@spawn println("doing nothing from thread $(Threads.threadid())")
Task (runnable) @0x00007fffb5b99e40
doing nothing from thread 2

julia> GC.gc(true)
finalizing a

As observed in JuliaGPU/CUDA.jl#866.

Metadata

Metadata

Assignees

No one assigned

    Labels

    GCGarbage collectormultithreadingBase.Threads and related functionality

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions