我是否需要手动销毁对象(如像素图)?
Do I ever need to manually destroy objects (like pixmaps)?
我正在编写一个基于 PySide2 的应用程序,其中包含一个 QScrollArea
,其中包含大量 QPixmap
图像(或更好:列表QLabel
又包含像素图)。该图像列表会随着时间的推移变得非常大,因此当达到一定数量时,我会定期从滚动区域中删除其中一些图像 - 这很好用。
不过,我的印象是,即使删除了一些图像,我的应用程序的内存消耗仍然相同。因此,删除标签小部件可能还不够。来自 QLayout.removeWidget()
上的 PySide2 文档:
Removes the widget widget from the layout. After this call, it is the caller’s responsibility to give the widget a reasonable geometry or to put the widget back into a layout or to explicitly hide it if necessary.
为了删除小部件,我执行了以下操作:
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()
所以我的问题是:我是否需要手动销毁我从布局中删除的 labels/pixmaps,或者它们应该自动被垃圾收集?
要理解操作,您必须有以下清晰的概念:
- 如果 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()
我正在编写一个基于 PySide2 的应用程序,其中包含一个 QScrollArea
,其中包含大量 QPixmap
图像(或更好:列表QLabel
又包含像素图)。该图像列表会随着时间的推移变得非常大,因此当达到一定数量时,我会定期从滚动区域中删除其中一些图像 - 这很好用。
不过,我的印象是,即使删除了一些图像,我的应用程序的内存消耗仍然相同。因此,删除标签小部件可能还不够。来自 QLayout.removeWidget()
上的 PySide2 文档:
Removes the widget widget from the layout. After this call, it is the caller’s responsibility to give the widget a reasonable geometry or to put the widget back into a layout or to explicitly hide it if necessary.
为了删除小部件,我执行了以下操作:
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()
所以我的问题是:我是否需要手动销毁我从布局中删除的 labels/pixmaps,或者它们应该自动被垃圾收集?
要理解操作,您必须有以下清晰的概念:
- 如果 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()