我是否需要手动销毁对象(例如像素图)?

时间:2020-05-08 14:15:48

标签: python memory-management pyside2 qlabel qpixmap

我正在写一个基于 PySide2 的应用程序,其中包括一个QScrollArea,其中包含许多QPixmap图像(或更优:QLabel的列表依次包含像素图)。该图像列表会随着时间的增长而变得很大,因此当达到一定数量时,我会定期从滚动区域中删除其中一些图像-效果很好。

但是,我确实给人的印象是,即使删除了一些图像,我的应用程序的内存消耗仍然相同。因此,删除标签小部件可能还不够。来自QLayout.removeWidget()上的PySide2文档:

从布局中删除小部件 widget 。通话后,调用方有责任为小部件提供合理的几何形状,或将其放回布局中,或在必要时显式隐藏它。

为了删除小部件,我执行以下操作:

while self.images_scroll_layout.count() > MAX_IMAGES:
    to_remove = self.images_scroll_layout.itemAt(self.images_scroll_layout.count() - 1)
    self.images_scroll_layout.removeItem(to_remove)
    to_remove.widget().deleteLater()

所以我的问题是:我是否需要手动销毁从布局中删除的标签/像素图,还是应该自动对其进行垃圾回收?

1 个答案:

答案 0 :(得分:2)

要了解该操作,您必须具有以下明确的概念:

  • 如果QObject具有父对象,则不会被GC删除。
  • 将小部件添加到布局时,该小部件将被设置为建立布局的小部件的子级。
  • 使用removeWidget()时,只有小部件会从处理布局的小部件列表中删除,因此,小部件的父级仍然是处理布局的小部件。

要验证,您可以使用以下代码,其中不会显示指示删除QObject的销毁信号。

from PySide2 import QtWidgets


class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.add_button = QtWidgets.QPushButton(self.tr("Add"), clicked=self.add_widget)
        self.remove_button = QtWidgets.QPushButton(
            self.tr("Remove"), clicked=self.remove_widget
        )

        scrollarea = QtWidgets.QScrollArea(widgetResizable=True)
        widget = QtWidgets.QWidget()
        scrollarea.setWidget(widget)

        lay = QtWidgets.QVBoxLayout(self)
        lay.addWidget(self.add_button)
        lay.addWidget(self.remove_button)
        lay.addWidget(scrollarea)

        self.resize(640, 480)

        self.label_layouts = QtWidgets.QVBoxLayout(widget)

        self.counter = 0

    def add_widget(self):
        label = QtWidgets.QLabel(f"label {self.counter}")
        self.label_layouts.addWidget(label)
        self.counter += 1

    def remove_widget(self):
        item = self.label_layouts.itemAt(0)
        if item is None:
            return
        widget = item.widget()
        if widget is None:
            return
        widget.destroyed.connect(print)
        print(f"widget: {widget} Parent: {widget.parentWidget()}")


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())

结论:不使用removeWidget()从内存中删除小部件,而仅使布局不处理该小部件,如果要删除小部件,则必须使用deleteLater()。

def remove_widget(self):
    item = self.label_layouts.itemAt(0)
    if item is None:
        return
    widget = item.widget()
    if widget is None:
        return
    widget.destroyed.connect(print)
    widget.deleteLater()