在 Kivy 中,为啥 popup.dismiss() 不从内存中删除弹出窗口?

Posted

技术标签:

【中文标题】在 Kivy 中,为啥 popup.dismiss() 不从内存中删除弹出窗口?【英文标题】:In Kivy, why doesn't popup.dismiss() delete the popup from memory?在 Kivy 中,为什么 popup.dismiss() 不从内存中删除弹出窗口? 【发布时间】:2016-01-10 07:36:27 【问题描述】:

我目前正在努力解决 Kivy 中的内存使用问题。

当一个弹出窗口被创建和打开时,内存使用量会增加一点(这是正常的),但是当用户关闭它时(使用dismiss()方法,关闭弹出窗口并将其从其父级中删除),内存没有释放。

因此,如果用户决定多次打开弹出窗口,程序最终会占用大量内存。这是我的代码的一部分,它通过创建、打开然后关闭弹出窗口 500 次来显示问题。

# py file
class OptionsView(Screen):

    def popupLoop(self):
        for x in range(0, 500):
            popup = self.MyPopup()
            popup.open()
            popup.dismiss()

    class MyPopup(Popup):
        pass


# kv file
<OptionsView>:
    BoxLayout:
        orientation: "vertical"
        Button:
            text: "Popup Loop"
            on_press: root.popupLoop()

<MyPopup>:
    size_hint: (.6, .6)
    title: "Confirmation"
    BoxLayout:
        Button:
            text: "Cancel"
            on_press: root.dismiss()

在 OptionView 屏幕中按下“Popup Loop”按钮会使程序的内存使用率从 1.2% 跃升至 11.7%(根据 top)。调整窗口大小(调用gc.collect())确实使这个数字降低了一点,但仍然很高。

如何防止这种情况发生? (请记住,我远不是 Python/Kivy 专家,所以即使解决方案对您来说真的很明显,请尝试向我解释!)

【问题讨论】:

CPython 可能只是保留内存以备将来使用。尝试打开和关闭 10,000 个弹出窗口。 @Joonazan 好吧,我不知道我的预期。 10 000 个弹出窗口只是让程序崩溃,没有任何错误。我可能只有 4GB 的 RAM,但这种行为仍然很不正常。 它们是同时打开的吗?如果一次只打开一个并且程序仍然崩溃,那么您就有内存泄漏。这在 Python 中是不可能的,但是这个库可能有问题或者需要你调用一些函数来释放内存。 @Joonazan 这确实是个问题:有时没有弹出窗口出现(所以我假设它们一个接一个地打开和关闭),而有时弹出窗口开始堆积,我不得不关闭他们手动。但在这两种情况下,内存使用量都会激增并且不会下降。我尝试将 gc.collect() 添加到 create/open/dismiss 循环中。这显着减缓了内存使用量的上升,但它仍然达到了非常高的水平并且没有回落。我仍然会检查 Kivy 文档,看看是否有你说的特殊功能。 【参考方案1】:

popup.dismiss() 不会立即从内存中删除弹出窗口。

也许这会有所帮助How to force deletion of a python object?

第二;关于为什么有时您的弹出窗口会被关闭而有时不会,您必须了解UI frameworks 需要使用事件进行编程。事件/进展不会以线性方式发生。

使用Clock 更好地测试您要检查的内容

    self.pops = 0
    Clock.schedule_once(self.test_pops)

def test_pops(self, dt):
    if self.pops > 10:
        return
    self.pops += 1
    pup = self.MyPopup()
    pup.bind(on_parent=self.dismiss_pup)
    pup.open()

def dismiss_pup(self, pup, parent)
    # popup was opened, please close it now
    pup.unbind(on_parent=self.dismiss_pup)
    pup.dismiss()
    Clock.schedule_once(self.test_pops)

不过,使用专门针对此的 Web 调试器模块会简单得多。

http://kivy.org/docs/api-kivy.modules.webdebugger.html

【讨论】:

以上是关于在 Kivy 中,为啥 popup.dismiss() 不从内存中删除弹出窗口?的主要内容,如果未能解决你的问题,请参考以下文章

为啥切换屏幕在 kivy 中不起作用?

在 kivy 样式文件中使用尖括号时,为啥我不断收到“无效语法”错误?

为啥不可能在 kivy 中制作 Markup TextInput?

为啥我不能在 main.py 中使用 kivy 添加图像?

Kivy:为啥 ScrollView 不能在 GridLayout 中工作?

为啥 kivy 应用程序中不显示下一个屏幕?