Looking at the log you provided in the GitHub issue, the internal per-thread
dispatcher (which is a `ref` object) is what causes the leak, as `.threadvar`'s
aren't destroyed on thread exit.
* * *
Not directly related to the leak, but the way you're using `cleanupThread`
doesn't guarantee that the list with potential cycle roots is empty on thread
termination. Consider the following:
type Cycle = ref object
x: Cycle
proc run() {.thread.} =
var x = Cycle()
x.x = x # create a cycle
discard x # make sure `x` is not moved
cleanupThread()
Run
In the case shown above, the cycle collector is run _before_ `x` goes out of
scope. When `x` goes out of scope, the referenced cell will be registered as a
potential cycle root (which allocates memory for ORC's root list), and you'll
thus get a memory leak.
To make sure that `cleanupThread` is called _after_ the thread's procedure
exits but _before_ thread destruction, you can use
`system.onThreadDestruction`, like so:
proc run() {.thread.} =
onThreadDestruction(cleanupThread)
# `cleanupThread` is invoked even if `run` exits due to an exception or
early return
...
Run
Of course, it'd be better if `Thread` cleans up after itself instead.