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

问题描述 投票:1回答:1

我正在写一个 PySide2-基于应用,其中包括 QScrollArea 盛产 QPixmap 图像(或更好的:一个列表 QLabel的图片,而这些图片又包含了pixmaps)。) 随着时间的推移,图片列表可能会越来越多,所以当达到一定数量时,我定期从滚动区域中删除其中的一些图片--效果不错。

然而,我的印象是,即使删除了一些图片,我的应用程序的内存消耗仍然是一样的。所以删除标签部件可能还不够。从PySide2的文档中可以看到 QLayout.removeWidget():

移除小组件 小部件 的布局中。在此调用后,调用者有责任给小组件一个合理的几何形状,或将小组件放回布局中,或在必要时明确隐藏它。

为了删除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()

所以我的问题是: 我是否需要手动销毁我从布局中移除的labelspixmaps,或者它们应该被自动垃圾回收?

python memory-management pyside2 qlabel qpixmap
1个回答
2
投票

为了理解这个操作,你必须有以下清晰的概念。

  • 如果一个QObject有一个父对象,那么它不会被GC删除。
  • 当一个widget被添加到布局中时,那么这个widget就会被设置为建立布局的widget的子节点。
  • 当使用removeWidget()时,那么只会从处理布局的widget列表中删除该widget,所以该widget的父节点仍然是处理布局的widget。

为了验证,你可以使用下面的代码,当一个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()不是用来从内存中删除widget的,只是让布局不处理该widget,如果要删除一个widget,必须使用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()
© www.soinside.com 2019 - 2024. All rights reserved.