PyQt中的信号处理程序是否会导致内存泄漏?

8

简短问题:

信号处理程序会造成内存泄漏吗?

长问题:

在C#中,如果我将处理程序附加到事件上,那么当事件触发时,处理程序的代码将执行。如果该处理程序分配了内存但未释放,是否会导致内存泄漏?如果是,有什么方法可以避免这种情况发生?

left_object.left_event += right_object.right_handler

当我摆脱 right_object 时,我需要删除处理程序,否则垃圾收集器将永远不会处理它(因为 left_object.left_event 保留了对 right_object 的指针)。

PyQt 信号和槽也是这样吗?

left_object.left_signal.connect( right_object.right_handler )

我从this问题中了解到,当left_objectright_object的析构函数被调用时,Qt会自动取消信号和槽之间的链接,但在Python中,我无法显式调用析构函数,并且right_handler是一个普通的函数。
我需要删除处理程序以防止right_object内存泄漏,还是PyQt使用某种弱引用技术?
虽然其中一个答案涉及此问题,this similar question提出了有关PyQt如何处理lambda表达式中的对象而不是如何处理信号的问题。

可能是重复问题:https://dev59.com/dKfja4cB1Zd3GeqPz7nu。 - ekhumoro
2个回答

1
这种设计可能会导致内存泄漏。如果这些连接包含引用,使得对象保持活动状态,则需要断开信号和插槽的连接。
是否出现这种情况取决于right_handler的具体情况。如果right_handler是带有对self的引用的闭包,则会出现此问题。

0
在Python中,我无法显式调用析构函数,
您可以在Python中调用析构函数。请查看del__del__ 我需要删除处理程序以防止right_objects内存泄漏吗?
不需要这样做。Python会处理它。运行下面的代码自己检查。
在这段代码中,startButton1stopButton1的信号被连接到Hello类对象的方法上,并且该对象(hello1)是Widget类的属性。因此,hello1将一直存在,直到Widget生命周期结束或者我们在Widget.onDelete方法中使用Delete按钮将其删除。一旦单击Delete按钮,将调用hello1的析构函数,它将超出范围。现在,startButton1stopButton1的信号不再像以前那样工作。

现在,在第二行中有startButton2stopButton2按钮,它们的信号与hello2对象连接。但是,一旦Widget构造完成,hello2的生命周期也结束了。因此,在Widget构造完成后,这些按钮的信号没有连接到任何插槽。

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_()

希望这可以消除你的疑虑。


1
这是不正确的。del并不会删除一个对象,它只是移除对它的一个引用。举个例子,如果你有foo.a = []foo.b = foo.a,然后del foo.b,对象仍然存在,因为它仍然被foo.a引用着。如果信号使对象保持活跃,正如原问题所问,那么del并不能解决这个问题。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接