PySide6中QRunnable设setAutoDelete(False)引发内存泄漏问题咨询
关于QRunnable与QThreadPool的生命周期问题解答
疑问1:设置task.setAutoDelete(False)是否会导致内存泄漏?
- 在PySide6 6.5.2/6.6.2版本中,若未保留Python层对Task对象的引用,确实会出现内存泄漏:QThreadPool的C实现会持续持有QRunnable的C对象引用,导致对应的Python包装器无法被垃圾回收器(GC)回收,即使手动调用
gc.collect()或程序关闭也无法触发__del__方法。 - 在PyQt6.6.1中无此问题:无论
autoDelete设为True或False,只要Python层的引用被释放,GC就能正常回收对象,触发__del__。 - 若主动保留Python层的Task对象引用(比如将task存储在全局容器中),在PyQt6.6.1中主动释放引用后可正常回收;但在PySide6的上述版本中,即使保留引用后再释放,仍无法触发
__del__,说明C++端的引用未正确释放。
疑问2:当设置task.setAutoDelete(True)时,QThreadPool应该删除QRunnable的C++对象还是Python包装器?
- 从Qt的C原生逻辑来说,
setAutoDelete(True)时,**QThreadPool会负责删除C的QRunnable对象**。 - 在Python绑定层:
- C对象被删除后,对应的Python包装器会失去底层的C实例支撑,随后会被Python的GC自动回收,触发
__del__方法。 - PyQt和PySide的绑定实现有差异:PyQt会更严谨地同步C对象与Python包装器的生命周期,而PySide6在
autoDelete=False时,C端的QThreadPool未正确释放对QRunnable对象的引用,导致Python包装器被“挂起”无法回收。
- C对象被删除后,对应的Python包装器会失去底层的C实例支撑,随后会被Python的GC自动回收,触发
复现验证说明
以下是复现代码(未保留Task引用):
import gc import sys import time from PySide6.QtCore import QRunnable, QThreadPool from PySide6.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout class Task(QRunnable): def __init__(self): super().__init__() def __del__(self): print('Task.__del__') def run(self): print('Task.run') time.sleep(3) print(f'Task.run finished') def run_task(): task = Task() task.setAutoDelete(False) # 注释此行则__del__正常触发 QThreadPool().globalInstance().start(task) def collect_by_gc(): collected_count = gc.collect() print(f'collected by GC: {collected_count}') def main(): app = QApplication(sys.argv) run_task_push_button = QPushButton('Run Task') run_task_push_button.clicked.connect(run_task) collect_by_gc_push_button = QPushButton('Collect by GC') collect_by_gc_push_button.clicked.connect(collect_by_gc) layout = QVBoxLayout() layout.addWidget(run_task_push_button) layout.addWidget(collect_by_gc_push_button) window = QWidget() window.setWindowTitle('Test App') window.setLayout(layout) window.show() app.exec() if __name__ == '__main__': main()
- 测试结果:点击“Run Task”后,任务执行完成但
__del__未被调用,手动触发GC也无效;将setAutoDelete(False)注释后,__del__会正常触发。 - 测试环境:Windows10(x64)、Python3.10.12
内容的提问来源于stack exchange,提问作者BlackHoleTracer
相关产品推荐
相关产品推荐

