Open JoshuaWebb opened 3 years ago
Any 3rd-party package can create non-deaomn threads without joining them at any point. Thus fixing the exec module only may not be a sufficient solution to prevent resource leakage.
This is true, that's how I discovered the issue in the first place. A more comprehensive fix is to patch the threading module in the version of Python that ships with Sublime, but depending on how long that will take, in the meantime one less leak is one less leak.
I am a bit shocked about the issue being known by python community without a fix for about 3 years now.
A more comprehensive fix is to patch the threading module in the version of Python that ships with Sublime
Even better: remove the module! And rely entirely on asyncio. No text editor needs threads for its plugins.
Description
There's currently an outstanding bug/issue in Python 3.7+ where non
daemon
python threads that end naturally but aren't ever checked for liveness e.g.is_alive()
, norjoin()
ed, leak a lock object. See https://bugs.python.org/issue37788The specifics are an implementation detail of CPython 3.8/threading.py, and the documentation doesn't mention requiring any specific calls to ensure timely resource cleanup of completed threads, but starting a (non daemon) thread places a lock object into a global set (
_shutdown_locks
) to be "joined" when python shuts down. This lock is removed from the set when you calljoin()
, or if you callis_alive()
on a thread after it has completed, but if you don't call either of those, this reference keeps the lock from being garbage collected along with any associated system resources (e.g. a Semaphore handle on Windows) until sublime exits.It looks like various fixes have already been proposed and at least one of them was merged (and subsequently reverted), so this issue will hopefully end up being resolved automatically in an upcoming version of Python, but it's unclear how soon that will happen.
NOTE: the
stderr_thread
is beingjoin()
ed inread_fileno()
(on thestdout_thread
), so only thestdout_thread
leaks its lock.Steps to reproduce
exec
build target.This can be verified in a via the console:
threading._shutdown_locks
This can also be verified externally using tools like Sysinternal's
handle.exe
; the following example callshandle
before doing any builds, and then once in between each build. There are some overhead Semaphores from the first build (33 up to 37), presumably some of the other global variables from threading, but then each subsequent build adds one more Semaphore handle.Expected behavior
The exec target should cleanup after itself, e.g. by marking them as daemon threads, or by joining/checking them after they are finished to remove the lock from the shutdown set.
Actual behavior
A small memory/resource leak for every single build.
Environment