信号处理程序是否可以在PyQt中泄漏内存?

问题描述 投票:5回答:2

简短问题:

可以通知处理程序内存泄漏。

长时间的问题:

在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使用某种弱引用?

python qt events pyqt signals-slots
2个回答
0
投票

此设计可能会发生内存泄漏。如果那些连接包含使对象保持活动状态的引用,则需要断开信号和插槽的连接。

是否实际发生取决于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_()

希望这会清除您的疑问。

© www.soinside.com 2019 - 2024. All rights reserved.