3

I'm currently struggling with a memory usage problem in Kivy.

When a popup is created and opened, memory usage goes up a little (which is normal), but when the user closes it (with the dismiss() method, which closes the popup and removes it from its parent), the memory isn't released.

So, if the user decides to open the popup a lot of times, the program will eventually use a lot of memory. Here is a part of my code that shows the problem by creating, opening and then dismissing a popup 500 times.

# 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()

Pressing the "Popup Loop" button in the OptionView screen causes the program to jump from 1.2% memory usage to 11.7% (according to top). Resizing the window (which calls gc.collect()) does bring this number down a little bit, but it remains really high.

How can I prevent this from happening? (Bear in mind that I'm far from being a Python/Kivy expert, so even if the solution is really obvious to you, please try to explain it to me!)

cometix
  • 31
  • 3
  • It might be that CPython just keeps the memory for possible future use. Try opening and closing 10 thousand popups. – Joonazan Oct 12 '15 at 18:22
  • @Joonazan Well, I don't know what I expected. 10 000 popups simply made the program crash, without any errors. I may only have 4gb of RAM, but this behavior is still really anormal. – cometix Oct 13 '15 at 03:52
  • Were they open at the same time? If only one was open at a time and the program still crashed, you have a memory leak. This is not possible in Python, but the library may be buggy or require you to call some function to free memory. – Joonazan Oct 13 '15 at 12:26
  • @Joonazan It really is buggy: sometimes none of the popups show up (so I assume that they get opened and closed one after the other), while sometimes the popups start piling up and I have to close them manually. But in both cases, memory usage explodes and doesn't go down. I tried adding gc.collect() to the create/open/dismiss loop. This significantly slowed down the rise of the memory usage, but it still attained very high levels and didn't go back down. I'll still check the Kivy docs to see if there's a special function like you said. – cometix Oct 13 '15 at 12:45

1 Answers1

2

popup.dismiss() will not remove the popup from memory immediately.

Maybe this will help How to force deletion of a python object?

Second; on why sometimes your popups get dismissed and sometimes they don't, you have to understand that UI frameworks need to be programmed using events. Events/progression do not happen in linear fashion.

Kivy events loop

Better test for what you are trying to check would be using 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)

It would be a lot simpler to just use the web debugger module geared towards this instead though.

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

Community
  • 1
  • 1
qua-non
  • 4,152
  • 1
  • 21
  • 25