问题
Short question:
Can signal handlers memory leak.
Long question:
In C#, if I attach a handler to an event
left_object.left_event += right_object.right_handler
Then I need to remove the handler when I get rid of right_object
or the garbage collector will never dispose of it (since left_object.left_event
retains a pointer to right_object
)
Is the same also true of PyQt signals and slots.
left_object.left_signal.connect( right_object.right_handler )
I see from this question that Qt automatically delinks signals and slots, when the destructor of either left_object
or right_object
is called, but in Python I cannot explicitly call the destructor, and right_handler
is a plain-old-function.
Do I need to remove the handler to prevent right_object
s memory-leaking, or does PyQt use some sort of weak-referencing?
While one of the answers touches on this, this similar question asks about how PyQt handles objects inside lambda expressions, not how PyQt handles signals.
回答1:
It is possible to have a memory leak with this design. You need to disconnect the signals and slots if those connections contain references which are keeping objects alive.
Whether or not this actually happens depends on what exactly right_handler
is. If right_handler
is a closure with a reference to self
then you have this problem.
回答2:
but in Python I cannot explicitly call the destructor,
You can call destructor in python. Check del and __del__
Do I need to remove the handler to prevent right_objects memory-leaking,
No, you don't need to do that. python will handle that. Run below code check your self.
In this code signal of startButton1
and stopButton1
are connected to methods of class object of Hello
and this object(hello1
) is attribute of Widget class. So hello1
will live until life object of Widget
OR we delete it in method Widget.onDelete
with Delete
button. Once you click Delete
button, destructor of hello1
is called and it will goes out of scope. Now signal of startButton1
and stopButton1
don't work as before.
Now in second row there are buttons startButton2
and stopButton2
, whose signal are connected with object of hello2
. But as soon as construct of Widget
is over hello2
life time is finish. So there is not slot connected for signal of those buttons after Widget
construct is over.
from PyQt5.QtWidgets import QApplication,QPushButton,QWidget,QHBoxLayout,QVBoxLayout
class Hello():
def __init__(self):
print("init")
def onStart(self):
print("onStart");
def onStop(self):
print("onStop");
def __del__(self):
print("del")
class Widget(QWidget):
def __init__(self,parent=None):
QWidget.__init__(self,parent);
vLayout = QVBoxLayout()
self.setLayout(vLayout)
buttons1 = QWidget()
hLayout1 = QHBoxLayout()
buttons1.setLayout(hLayout1)
vLayout.addWidget(buttons1)
startButton1 = QPushButton("Start");
stopButton1 = QPushButton("Stop");
deleteButton1 = QPushButton("Delete");
self.hello1 = Hello();
startButton1.clicked.connect(self.hello1.onStart)
stopButton1.clicked.connect(self.hello1.onStop)
deleteButton1.clicked.connect(self.onDelete)
hLayout1.addWidget(startButton1);
hLayout1.addWidget(stopButton1);
hLayout1.addWidget(deleteButton1);
buttons2 = QWidget()
hLayout2 = QHBoxLayout()
buttons2.setLayout(hLayout2)
vLayout.addWidget(buttons2)
startButton2 = QPushButton("Start");
stopButton2 = QPushButton("Stop");
deleteButton = QPushButton("Delete");
hello2 = Hello();
startButton2.clicked.connect(hello2.onStart)
stopButton2.clicked.connect(hello2.onStop)
hLayout2.addWidget(startButton2);
hLayout2.addWidget(stopButton2);
def onDelete(self):
if hasattr(self,"hello1"):
del self.hello1
app = QApplication([])
w = Widget();
w.show()
app.exec_()
Hope this will clear you doubt.
来源:https://stackoverflow.com/questions/43937179/can-signal-handlers-memory-leak-in-pyqt