【问题标题】:How to empty the RAM after closing the second Window?关闭第二个窗口后如何清空 RAM?
【发布时间】:2019-04-26 15:05:59
【问题描述】:

在示例中,当程序运行时,占用了 18 MB 的 RAM。当第二个窗口运行时,另外 4 MB 将被 RAM 占用。当我们关闭第二个 Window 时,所占用的内存不会返回到 RAM,如果第二次打开第二个 Window,那么又会占用 4MB 的 RAM。你对这个问题的解决方案是什么? 这个例子是 PyQt4 而我的应用是 PyQt5。

这个例子来自这个链接: PyQT: how to open new window

如果可能,提出一个程序,用原理方法打开第二个窗口,关闭后不占用RAM空间。

from PyQt4 import QtGui, QtCore
import sys

class Second(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(Second, self).__init__(parent)


class First(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(First, self).__init__(parent)
        self.pushButton = QtGui.QPushButton("click me")
        self.setCentralWidget(self.pushButton)

        self.pushButton.clicked.connect(self.on_pushButton_clicked)
        self.dialogs = list()

    def on_pushButton_clicked(self):
        dialog = Second(self)
        self.dialogs.append(dialog)
        dialog.show()

    def main():
        app = QtGui.QApplication(sys.argv)
        main = First()
        main.show()
        sys.exit(app.exec_())

if __name__ == '__main__':
    main()

PyQt5 中的示例

from PyQt5 import QtCore, QtGui, QtWidgets, uic
import sys

class Second(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(Second, self).__init__(parent)


class First(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(First, self).__init__(parent)
        self.pushButton = QtWidgets.QPushButton("click me")
        self.setCentralWidget(self.pushButton)

        self.pushButton.clicked.connect(self.on_pushButton_clicked)
        self.dialogs = list()


    def on_pushButton_clicked(self):
        dialog = Second(self)
        self.dialogs.append(dialog)
        dialog.show()


def main():
    app = QtWidgets.QApplication(sys.argv)
    main = First()
    main.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

【问题讨论】:

  • 只是好奇,您为什么要保留打开的窗口列表?
  • 我刚刚写了例子
  • 问题是 PyQt 自己管理所有这些东西——一旦你销毁了对象的所有实例,它就会从内存中消失。您应该尝试从列表中删除关闭的窗口,看看您的内存使用量是否下降。
  • @DanialAminiMoghadam 你如何测量内存使用情况?
  • @icwebndev 列表中打开的窗口的名称是否保存?如果是这样,我如何访问它们并将它们从列表中删除?

标签: python pyqt pyqt5


【解决方案1】:

在 PyQt 中,根据您配置对象的方式,您的属性可以由 C++ 或 Python 管理。对于 QObject(例如 QMainWindow),如果传递了父级,则内存处理是 C++,并且 Qt 规则指示只有当父级死亡或子级被 deleteLater 显式删除时,子级才会死亡。所以 Second 的生命周期取决于 First,也就是说,即使你关闭了窗口,对象也不会被删除。关闭窗口时要删除的窗口必须激活属性Qt::WA_DeleteOnClose,所以解决方法是在Second类中添加:

class Second(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(Second, self).__init__(parent)
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose) # <---

如果您打算使用容器来保存对象的引用,您可能会遇到问题,因为当 C++ 删除对象时它不会通知容器。因此,有以下选项可以避免这些问题:

  • 不要使用容器。
  • 使用weakref.ref(),这样当对象被删除时,它也会从容器中移除:
def on_pushButton_clicked(self):
    dialog = Second(self)
    self.dialogs.append(weakref.ref(dialog, self.dialogs.remove))
    dialog.show()
  • 使用被破坏的信号从容器中移除对象:
import sip
# ...
class First(QtWidgets.QMainWindow):
    # ...
    def on_pushButton_clicked(self):
        dialog = Second(self)
        dialog.destroyed.connect(self.on_destroyed)
        self.dialogs.append(dialog)
        dialog.show()

    @QtCore.pyqtSlot('QObject*')
    def on_destroyed(self, obj):
        self.dialogs = [dialog for dialog in self.dialogs if not sip.isdeleted(dialog)]

【讨论】:

  • 除非您在其他地方引用Second 类对象,否则这绝对可以正常工作。并且 OP 正在使用 dialogs list
  • @icwebndev 哪个列表?,即使有一个容器,它只存储了递延变量,因为 C++ 消除了变量而不是对变量的引用。
  • @icwebndev 正如您所指出的,即使使用容器,窗口的内存也已被删除,该列表将仅存储指向未保留地址的变量,供您检查添加以下代码import sip QtCore.QTimer(self, interval=1000, timeout= lambda: print([sip.isdeleted(dialog) for dialog in self.dialogs])).start()self.dialogs = list() 之后
  • @icwebndev [cont.] 所以内存被删除了,但指向该内存的变量没有得到通知,所以正确的做法可能是不使用容器,或者使用弱引用,或者简单地删除在销毁信号的帮助下列表中的变量
  • @icwebndev 我已经添加了关于你所指出内容的解释。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多