memory seems to keep deleted widgets

1,411 views
Skip to first unread message

peer mocks

unread,
Jun 7, 2013, 4:07:42 AM6/7/13
to kivy-...@googlegroups.com
Hi,

I've got a problem with deleted widgets. It seemes, that they are kept in the memory.

I've got a GridLayout in a TabbedPanel. Inside of the GridLayout are a lot of Widgets (including Images), which are loaded
and deleted a lot of times. After a while, kivy takes up to 1GB of memory, although I deleted all of my widgets inside the
Panel.

Do I have to delete them by code? Aren't they collected by the python garbage collector automatically?

Greetings,
Peer

Akshay Arora

unread,
Jun 7, 2013, 5:25:23 AM6/7/13
to kivy-...@googlegroups.com
Make sure you aren't maintaining a reference to the widget's  being removed, Python only Garbage collects objects once all known references to them have been removed.



--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Stas Zytkiewicz

unread,
Jun 7, 2013, 7:57:11 AM6/7/13
to kivy-...@googlegroups.com
Just wasted a couple of hours on pretty much the same symptoms :-(
Don't know if it's a bug or a feature.

I've got a controller object that loads modules and instantiates classes which in turn handle objects build by their kv file.
(sound horrible, I know but it's a really big project)
But now the problem:
When a module is loaded and its kv object is build the first time there are 4 kivy widgets added to it.
Then the module is 'finished' and another module is loaded etc.
Then at some point the controller is loading the first module again and it's kv object is build again and the 4 widgets are added to it.
But now i have 8! widgets in this object, 2 sets of 4 ?!

I've tried everything from reloading the module iso just importing, hardcoded deleting of the objects nothing, clearing the kivy Cache, even keeping track of the references in the python garbage collector, .... nothing.
Then I suspected the kv file and kivy Builder.
When I manually unload the kv file from the kivy Builder object as a last step when my module is 'finished' I don't have multiple objects when I reload and rebuild my objects !

Very weird, perhaps it's a result of my design but I feel it's a bug and not a feature.

Akshay Arora

unread,
Jun 7, 2013, 10:14:34 AM6/7/13
to kivy-...@googlegroups.com
Try to reduce your code to just a small snippet that still reproduces the issue and post it here.
Otherwise it's just like guesswork, can't really just guess what issue you are facing.

Regards

Stas Zytkiewicz

unread,
Jun 7, 2013, 10:22:25 AM6/7/13
to kivy-...@googlegroups.com

I will try to come up with some code this weekend.

You received this message because you are subscribed to a topic in the Google Groups "Kivy users support" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/kivy-users/2lbadbUQxDk/unsubscribe?hl=en.
To unsubscribe from this group and all its topics, send an email to kivy-users+...@googlegroups.com.

peer mocks

unread,
Jun 7, 2013, 10:46:04 AM6/7/13
to kivy-...@googlegroups.com
Hi,

this is a short example where I found the same behavior. When you add 10 or more widgets, you'll notice, that the kivy process is getting larger.
After deleting the tabs, it stays the same.

# -*- coding: utf-8 -*-
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.tabbedpanel import TabbedPanel, TabbedPanelHeader
from kivy.uix.button import Button


class TabPanel(TabbedPanel):
   
   
def add_header(self):
       
        x
= BoxLayout()
        x
.add_widget(Button(text = 'left'))
       
        z
= CloseableHeader(panel = self, content = x)        
       
self.add_widget(z)
       
        uidNewTab
= self.tab_list[0].uid  
       
self.tab_list[0].text = str(uidNewTab)    
       
self.tab_list[0].content.add_widget(Button(text = 'right'))

       
print self.tab_list
       
print '###########'
       
class CloseableHeader(TabbedPanelHeader):
   
pass


class TestTabApp(App):
   
   
def build(self):
       
        root
= self.root
        tab
= TabPanel()
        root
.add_widget(tab)
        tab
.do_default_tab = False    
       

       
if __name__ == '__main__':
   
TestTabApp().run()




#:kivy 1.0
#:import kivy kivy
#:import win kivy.core.window



BoxLayout:    

<CloseableHeader>
    color
: 0,1,0,1
    size_hint_x
: None
    width
: self.texture_size[0] + 20
   
   
BoxLayout:
        pos
: root.pos
        size
: root.size
        padding
: 10

           
       
BoxLayout:
            size_hint
: None, 1
            orientation
: 'vertical'
            width
: 22                                                                    
           
Image:
                source
: 'tools/theming/defaulttheme/close.png'      
                on_touch_down
:
                   
if self.collide_point(*args[1].pos) : root.panel.remove_widget(root)
                   
if self.collide_point(*args[1].pos) : root.OldTabList = root.panel.tab_list


<TabPanel>
   
   
FloatLayout:  
       
BoxLayout:
            id
: tab_1_content
            pos
:self.parent.pos
            size
: self.parent.size
           
           
BubbleButton:
                text
: 'Press to add new tab'
                on_release
: root.add_header()
 
   
CloseableHeader:
        id
: tab1
        text
: str(self.uid)
        content
: tab_1_content
        panel
: root


peer mocks

unread,
Jun 7, 2013, 12:53:47 PM6/7/13
to kivy-...@googlegroups.com
Here is an more reduced example. It has nothing to do with the TabbedPanel. It has to do with the deleting of widgets in general.

# -*- coding: utf-8 -*-
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button


class Field(BoxLayout):
   
   
def add_header(self):        
        x
= MyButton()
       
self.add_widget(x)
 
class MyButton(Button):
   
def delete(self):
       
self.parent.remove_widget(self)

class abcApp(App):    
   
def build(self):      
        root
= self.root
        f
= Field()
        root
.add_widget(f)
       
if __name__ == '__main__':
    abcApp
().run()




#:kivy 1.0
#:import kivy kivy
#:import win kivy.core.window


BoxLayout:    

<MyButton>
    on_press
: self.delete()
   

<Field>  
   
BoxLayout:

Akshay Arora

unread,
Jun 7, 2013, 3:34:53 PM6/7/13
to kivy-...@googlegroups.com
You can use a tool (webdebugger) provided with kivy to test this further.

python main.py -m webdebugger

And open http://localhost:5000/ in a browser

"Requires flask"

What I see with that tool and the example above is that python garbage
collector doesn't get called immediately and can wait sometimes tool long
before collecting.

This is how I tested. I press the `press to add button`
multiple times to add multiple Buttons (you can see the no of python
objects increase) and then remove these buttons. The no of python objects
remain constant for a long time before being garbage collected.

Now If I do any non continuous operation like add a widget in between removing
the widgets or vice-versa. The objects get garbage collected. Maybe the Python
Garbage collector disables itself when it detects continuous operation(for speed)?
I don't really know but I know there is a way to explicitly force garbage collection
gc.collect().

Be careful about where you put it though and don't put it inside a loop or a function
that get's called a lot that could slow the app down.

Hope that helps.


peer mocks

unread,
Jun 8, 2013, 6:27:41 AM6/8/13
to kivy-...@googlegroups.com
Thanks for your reply. I didn't know about the webdebugger. Seems to be a handy tool.

The webdebugger doesn't show me any reduction of the python objects and the garbage is always zero.
Also the garbage collector didn't help. gc.collect() doesn't cause any changes, no matter where I put it.

Do you think that this is a python issue? Or is it more up to kivy?
For me this is quite important. An app which needs 500mb to 1GB memory still won't make much sense on a phone or tablet.

best regards,
Peer

peer mocks

unread,
Jun 8, 2013, 8:56:33 AM6/8/13
to kivy-...@googlegroups.com
I did this little programm to see, how it's working in normal python:

import gc

def one():
    userInput
= input('Give me a value')#1
    y
= {}
   
for a in range (1000000):
        y
[a] = userInput
    userInput
= input('Give me a value')#2
   
del y
   
def two():
    userInput
= input('Give me a value')#3
    gc
.collect()
    userInput
= input('Give me a value')#4
   
one
()
two
()


When you run it, you'll see the size of the prozess pythonw.exe:
on start: ~2.600 kb
after #1: ~40.000kb
after #2:  ~15.000kb
after #3: ~ 4.000kb

Python collects at least half of the garbage after loosing the reference on y, and mostly the rest after telling explicit to do so.

So I think, there must be some code, where kivy keeps the reference on created widgets.


best,
Peer
 

Akshay Arora

unread,
Jun 8, 2013, 4:55:35 PM6/8/13
to kivy-...@googlegroups.com
let's try to automate this a bit ::

```
from kivy.app import App

from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.clock import Clock

class my1App(App):
    count = 1

    def build(self):
        Clock.schedule_interval(self.do_widgets, 1./60.)
        return BoxLayout()

    def do_widgets(self, dt):
        if self.count > 59:
            self.root.clear_widgets()
            self.count = 1
        else:
            self.count += 1
            self.root.add_widget(Button(text='Hello'))
           
if __name__ == '__main__':
    my1App().run()
```

Here I add 58(59 first time) widgets every second and clear them.
Running this app for 100 secs means roughly 5801 widgets added  and removed.
After 100 secs the memory used by this app was 60.6. I wonder what you are doing that leads to 500+MB of usage.

You can run this app with the webdebugger and see the no of python objects spike up and down.

I know we would need a lot more thorough testing to check for memory leaks,  but just for testing
simple widget addition and deletion this small test seems to indicate that addition/deletion should not lead to 500+MB of mem usage
unless you are just adding widgets and not removing them.



Peer
 

peer mocks

unread,
Jun 10, 2013, 6:05:49 AM6/10/13
to kivy-...@googlegroups.com
I think I found the error, if it's really an error.
The size of the programm differs depending on how I start it.

When I start your code from the console (kivy.bat) with "kivy main.py -m webdebugger", the programm starts
with ~40mb and increases in the next minutes to ~45/49 mb. Then the size stays stable.
I can see the the amount of python objects increasing/decreasing the whole time.
(btw, garbage is zero the whole time. what does it count?)

When I start your code with a double click on main.py (on Windows 7/ I didn't try Ubuntu yet), the programm
also starts around ~40mb, but then never stops growing. So after 1 hour of running, the size increases up to 170 mb.
As my programm is of course a lot larger then your code, I easily reach 500mb+.

I have some issues with utf-8 decoding in my programm at the moment, so I can't try it. But as soon as the issues will be solved, I will try to
start my programm via the console and have a look, if it works as well.

I only builded an app for android, not for windows untill now. So I have to examine it more and see, how sizes of an app behave in Ubuntu,Android and Windows.

regards,
Peer


Akshay Arora

unread,
Jun 10, 2013, 7:37:07 AM6/10/13
to kivy-...@googlegroups.com

When I start your code with a double click on main.py (on Windows 7/ I didn't try Ubuntu yet), the programm
also starts around ~40mb, but then never stops growing. So after 1 hour of running, the size increases up to 170 mb.
As my programm is of course a lot larger then your code, I easily reach 500mb+.

That's so weird,  garbage collection should not be different depending on where you launch your app from.
Would you please file a bug on http://github.com/kivy/kivy/issues. Mentioning the procedure to reproduce the buggy behaviour.

Regards.

Stas Zytkiewicz

unread,
Jun 10, 2013, 8:49:33 AM6/10/13
to kivy-...@googlegroups.com
On 06/07/2013 04:14 PM, Akshay Arora wrote:
> Try to reduce your code to just a small snippet that still reproduces
> the issue and post it here.
> Otherwise it's just like guesswork, can't really just guess what issue
> you are facing.
I've tried to extract the code into smaller snippets but then I don't
have issues. In the project we extend classes that also loads kv files
of their ow so I suspect that it might be the cause of the problem.
I will keep trying to get it reproduced in smaller code bits.
(And by doing so perhaps fix my own issue :-)
> from it, send an email to kivy-users+...@__googlegroups.com.
>
> For more options, visit
> https://groups.google.com/__groups/opt_out
> <https://groups.google.com/groups/opt_out>.
>
>
>
> --
> You received this message because you are subscribed to the Google
> Groups "Kivy users support" group.
> To unsubscribe from this group and stop receiving emails from it,
> send an email to kivy-users+...@googlegroups.com
> <mailto:kivy-users%2Bunsu...@googlegroups.com>.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>
>
> --
> You received this message because you are subscribed to a topic in the
> Google Groups "Kivy users support" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/d/topic/kivy-users/2lbadbUQxDk/unsubscribe?hl=en.
> To unsubscribe from this group and all its topics, send an email to
Greetings,
Stas Zytkiewicz

J.H

unread,
Jun 20, 2013, 9:15:15 PM6/20/13
to kivy-...@googlegroups.com
Hello,

Maybe, Memprof can help you to find ?

http://jmdana.github.io/memprof/

J.H

Reply all
Reply to author
Forward
0 new messages