I am running this simple SignalManager class to manage running and closing some QThreads spawned by Parent. And this seems to work without a fuss in non-debugging mode. GUI uses around 480 MB and one thread adds roughly 120 MB of RAM and the memory used by the thread is freed once I hit the button responsible for closing the thread. What I wonder about is why in debugging mode the Dummy-N thread is considered as Running even after closing it. I use latest versions of VSCode (1.97.2) and Microsoft Python Debugger (2025.1.2025022401). Python 3.11.6, PyQt5 version 5.15.10. class Parent(QMainWindow, SignalManager): def __init__(self): super().__init__() self.signalmanager = SignalManager(self) # other parent class definitions class SignalManager: def __init__(self, parent): super().__init__() self.parent = parent def start_signal_generator(self, channel: int, connector_state: bool): if channel == 1: # Ensure the previous thread is properly finished if hasattr(self, "channel1_thread") and self.channel1_thread is not None: self.stop_signal_generator(channel) # Define worker thread self.channel1_thread = QThread() self.running_threads.append(self.channel1_thread) self.channel1_generator = SignalGenerator(self.parent, channel, connector_state) self.channel1_generator.moveToThread(self.channel1_thread) self.channel1_thread.started.connect(self.channel1_generator.run) self.channel1_generator.finished.connect(self.channel1_thread.quit) self.channel1_generator.finished.connect(self.channel1_generator.deleteLater) self.channel1_thread.finished.connect(self.channel1_thread.deleteLater) self.channel1_generator.progress.connect(self._reportProgress) self.parent.connector1_toggled.connect(lambda state: self.channel1_generator.update_connector_state(state)) self.channel1_thread.start() else: logging.debug("Invalid channel number.") def stop_signal_generator(self, channel): if channel == 1 and self.channel1_thread is not None and self.channel1_generator.is_running(): self.channel1_generator.stop() self.channel1_thread.quit() self.channel1_thread.wait() self.channel1_thread = None print("Thread for channel 1 quitted.") else: logging.debug("Invalid channel number.") def _reportProgress(self, channel, t, wfm): pass class SignalGenerator(QObject): finished = pyqtSignal() progress = pyqtSignal(int, object, object) def __init__(self, parent, *args, **kwargs): super().__init__() self.parent = parent self.running = True # Some other class instance definitions def run(self): """Long-running task of generating/updating the signal""" debugpy.debug_this_thread() # this is for debugging inside `QThread`s (probable culprit of persistent threads in VSCode callstack) while self.running: if not self.running: break time.sleep(1) self.progress.emit(1,[1,2,3],[1,2,3]) self.finished.emit() self.stop() def stop(self): self.running = False def is_running(self): return self.running launch.json { // Use IntelliSense to learn about possible attributes. // Hover to view descriptions of existing attributes. // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "name": "Python Debugger: Current File in Current Workspace with Qt", "type": "debugpy", "request": "launch", "program": "${workspaceFolder}/__main__.py", "console": "integratedTerminal", "cwd": "${workspaceFolder}", "justMyCode": false } } Continue reading...