KivyMD: Dismissing a list item (to GC)

List items apparently are not garbage collected.

Here is a Hello World like app with two buttons. The big one populates a list with 50 items, the little one clears it. Memory usage inspection I’m running like this:

$ mprof run --include-children python leak.py 
...
$ mprof plot --output out.png

The required software is matplotlib and memory-profiler. Whenever you run the test, creating and then clearing the list several times by clicking the buttons, you get a plot like a steadily ascending stairway. How am I supposed to convince Kivy(MD) to release the items no longer needed?

leak.py:

from functools import partial
import kivy

kivy.require("1.11.1")
from kivy.utils import platform

print(f"platform: {platform}")

from kivy.lang import Builder
from kivy.uix.floatlayout import FloatLayout

from kivymd.app import MDApp
from kivymd.uix.tab import MDTabsBase
from kivymd.uix.list import TwoLineAvatarIconListItem
import gc


ACTION_ICON = "eye"


class PowerListItem(TwoLineAvatarIconListItem):
    """The engaged power supply item."""


class TabList(FloatLayout, MDTabsBase):
    """The engaged power supplies tab."""

    def surfacing(self, tab_text):
        pass

    def discover(self, cnt):
        ids = MDApp.get_running_app().root.ids
        for i in range(cnt):
            item = PowerListItem(
                text="List Item" + f" {i + 1:>2}", secondary_text="none"
            )
            ids.ps_list.add_widget(item)


class Contero(MDApp):

    def build(self):
        return Builder.load_file("leak.kv")

    def on_start(self):
        self.theme_cls.primary_palette = "Gray"

    def discovery_clean(self):
        for item in self.root.ids.ps_list.children:
            print(f"item: {item.text}")
        self.root.ids.ps_list.clear_widgets()
        gc.collect()

    def discovery_request(self, item_count=50):
        self.discovery_clean()

        tab_list = self.root.ids.ps_tab_list

        tab_list.discover(item_count)

    def on_tab_switch(self, instance_tabs, instance_tab, instance_tab_label, tab_text):
        """Called when switching tabs.
        """

        instance_tab.surfacing(tab_text)


if __name__ == "__main__":
    Contero().run()

leak.kv:

#:kivy 1.11.1
#:import ACTION_ICON __main__.ACTION_ICON
BoxLayout:
    orientation: "vertical"
    MDTabs:
        id: ps_tabs
        on_tab_switch: app.on_tab_switch(*args)
        TabList:
            id: ps_tab_list
            text: "flash"
            ScrollView:
                bar_margin: 5
                bar_width: 15
                bar_color: .0, .8, .0, 1
                bar_inactive_color: .5, .5, .5, 1
                effect_cls: "ScrollEffect"
                scroll_type: ["bars", "content"]
                scroll_distance: 5
                scroll_timeout: 50
                MDList:
                    id: ps_list
    MDBottomAppBar:
        MDToolbar:
            id: ps_toolbar
            title: "Destroy a list"
            icon: ACTION_ICON
            type: "bottom"
            on_action_button: app.discovery_request()
            right_action_items: [ ['minus-box-outline', lambda x: app.discovery_clean()], ]


<PowerListItem>:
    IconLeftWidget:
        id: item_left
        icon: "earth"

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 32 (17 by maintainers)

Most upvoted comments

@mozesa

Later on I only change the corresponding (as regards me text) attribute of them.

This is a good practice advised by the Kivy developers.

@mozesa I have already explained 100 times to you - Kivy never released up memory!