Title: Subprocess Thread handles grow with each call and aren't released [Windows]
Type: resource usage Stage: resolved
Components: Interpreter Core, Windows Versions: Python 3.6
Status: closed Resolution: third party
Dependencies: Superseder:
Assigned To: Nosy List: GranPrego, eryksun, giampaolo.rodola, gregory.p.smith, paul.moore, steve.dower, tim.golden, zach.ware
Priority: normal Keywords:

Created on 2018-05-22 14:59 by GranPrego, last changed 2021-03-16 03:15 by eryksun. This issue is now closed.

File name Uploaded Description Edit GranPrego, 2018-05-23 11:18
Messages (6)
msg317296 - (view) Author: GranPrego (GranPrego) Date: 2018-05-22 14:59
On windows 7 / 10 I'm using subprocess to launch a dos cmdline executable and returning the results, which is all working fine.
However, each time I make a call, the Python handle count is gradually increasing, jumping up , back a few, then jumping up and so on.

All the handles are released when the script exits, but quite often python just hangs after a few hours.  If I use process explorer to investigate I can see that python has an increasing number of Thread handles, even though I can see the process being called and cleanly exiting.

Unfortunately I'm stuck with the dos executable and it's always a one shot of sending it a single command each time and the script calls it a lot. The executable is just taking a string cmdline and returning a couple of lines of text and then exiting.  It only runs for a couple of seconds at most.

I've tried two variants of calling the process, I was hoping that the with variant would clean up, but there is no difference.

Each handle object that gets left behind has a single reference and a non paged quota of 1192, 0 paged.

The script is long running and I've seen the handle count reach 46K.

result = ""
with Popen ([fcptool, parameters],  stdout=PIPE, universal_newlines=True, bufsize=1) as process:
        for line in process.stdout:
            result = result + line

return result
p =[fcptool, parameters], stdout=subprocess.PIPE,              stderr=subprocess.STDOUT, universal_newlines=True, shell=True).stdout

return p

I can reproduce this on 3 different machines, 2 windows 7 and one windows 10, all Python 3.6.   I can't see a way around this at the moment and as far as I can tell, I'm using the call to subprocess correctly.
msg317312 - (view) Author: Eryk Sun (eryksun) * (Python triager) Date: 2018-05-22 17:41
The thread handle that CreateProcess returns gets immediately closed in Popen._execute_child, so I can't see how this is due to subprocess. Please check to make sure these thread handles aren't for threads in your own process. Set the lower pane of Process Explorer to show the handle list. For a thread handle, the name field shows the executable name and PID of the process to which the thread is attached.
msg317318 - (view) Author: GranPrego (GranPrego) Date: 2018-05-22 18:08
Process explorer is showing the handles as belonging to the python executable. I can see the cmd process start,then the executable which terminates cleanly.  I can see thread handles appearing under the python process, with some terminating, but more green than red, hence the increase.  I can post a screenshot tomorrow. Thanks
msg317323 - (view) Author: Eryk Sun (eryksun) * (Python triager) Date: 2018-05-22 18:57
The 2nd example with creates two threads in the Python process, since you're redirecting both stdout and stderr to pipes and run() calls communicate(). The first example with subprocess.Popen() shouldn't create any threads. In either case, nothing in subprocess should be opening a handle for a thread.

Please attach a minimal script that reproduces the problem, preferably running a command everyone can test such as "python.exe -V" and preferably with shell=False if the problem can be reproduced without the shell. Also, describe your Python setup, i.e. the installed distribution and packages. Something could be monkey patching the subprocess module.
msg317384 - (view) Author: GranPrego (GranPrego) Date: 2018-05-23 11:18
I'm now pretty convinced that sounddevice 0.3.11 library is the culprit, which may in turn point to the portaudio library, or CFFI.

I make a call to just before calling subprocess to run the dos cmd, the timing was such that process explorer would make it look like the leak was occurring during the subprocess call, but isolating the  shows that it causing the two additional Thread handles to be created and never released until the script ends (which could be 1-48 hours or more)

Another section of the code was using sd._terminate() and sd._initialize() to work around a buffersize problem with sounddevice and these calls also leak thread handles.

I've cut the program down as much as possible and the following now shows the problem without the call to subprocess.  You'll need to change the sd.default.device to an appropriate sound card.

Thanks for the quick responses.  If you're happy that this is the correct analysis of issue then perhaps it could be reclassified as a different component or I can get in touch with the sounddevice author.

msg317387 - (view) Author: Giampaolo Rodola' (giampaolo.rodola) * (Python committer) Date: 2018-05-23 11:56
FYI, there's psutil.Process().num_handles() which you can use to count handles before and after subprocess invocation.
Date User Action Args
2021-03-16 03:15:14eryksunsetstatus: open -> closed
resolution: third party
stage: resolved
2018-05-23 11:56:16giampaolo.rodolasetmessages: + msg317387
2018-05-23 11:18:29GranPregosetfiles: +

messages: + msg317384
2018-05-22 19:13:11gregory.p.smithsettitle: Subprocess Thread handles grow with each call and aren't released until script ends -> Subprocess Thread handles grow with each call and aren't released [Windows]
2018-05-22 18:57:01eryksunsetmessages: + msg317323
2018-05-22 18:08:13GranPregosetmessages: + msg317318
2018-05-22 17:57:21pitrousetnosy: + gregory.p.smith, giampaolo.rodola
2018-05-22 17:41:00eryksunsetnosy: + eryksun
messages: + msg317312
2018-05-22 14:59:21GranPregocreate