Open mdickinson opened 7 years ago
Note: this was on OS X 10.9. I haven't tested on other platforms, but I don't have any reason to suspect that the bug is platform-dependent.
Here's the leak, reduced to its PySide essentials. I'm looking for some sort of cleanup operation I can do to undo the leak, but I haven't found anything yet.
from PySide import QtCore
from PySide import QtGui
demonstrate_refleak = True
class MyTableModel(QtCore.QAbstractTableModel):
def rowCount(self, mi):
return 2
def columnCount(self, mi):
return 2
def data(self, mi, role):
return 'spam' if role == QtCore.Qt.DisplayRole else None
class MyWindow(QtGui.QWidget):
def __init__(self, *args):
QtGui.QWidget.__init__(self, *args)
self.table_model = MyTableModel()
self.table_view = QtGui.QTableView()
if demonstrate_refleak:
# The use of the proxy seems to lead to the refleak.
self.proxy_model = QtGui.QSortFilterProxyModel()
self.proxy_model.setSourceModel(self.table_model)
self.table_view.setModel(self.proxy_model)
else:
# Version that doesn't leak.
self.table_view.setModel(self.table_model)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.table_view)
self.setLayout(layout)
def main():
app = QtGui.QApplication.instance()
if app is None:
app = QtGui.QApplication([])
win = MyWindow()
win.show()
app.exec_()
if __name__ == '__main__':
import gc
for _ in range(4):
main()
while gc.collect():
pass
table_models = [obj for obj in gc.get_objects() if isinstance(obj, MyTableModel)]
print "Number of live MyTableModel instances: ", len(table_models)
The leak doesn't occur under PyQt4 (though I do get error messages of the form "QObject::startTimer: QTimer can only be used with threads started with QThread").
Possible fix is to handle the sorting/filtering ourselves rather than relying on PySide to do it. Downsides would be additional complexity on the Python side, plus possibly less-nice user experience (eg. when you sort, does the selection update correctly?)
Under Qt4 / PySide, the
TableEditor
creates an uncollectableTableModel
object.Here's some code that exercises the bug:
When I run the above, after dismissing the UI four times, I get:
The
TableModel
objects in question have no references to them (excluding thetable_models
list itself), according togc.get_referrers
. I suspect that some PySide signal handler is incrementing the reference count of theTableModel
and never doing the corresponding decrement.