kmonsoor / pyglet

Automatically exported from code.google.com/p/pyglet
BSD 3-Clause "New" or "Revised" License
0 stars 0 forks source link

Memory leak in text.Label #476

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
The following program leaks about 300 KB per second on my machine (Windows
XP, Python 2.6.5, pyglet 1.1.4, NVIDIA Quadro FX 360M (but I can observe
the same on an Intel 855GME)):

--8<-------------------------------------------------------------
import pyglet

w = pyglet.window.Window()

while not w.has_exit:
    w.dispatch_events()
    w.clear()
    l = pyglet.text.Label("abc", font_size=w.height,
                          x=w.width/2, y=w.height/2,
                          anchor_x="center", anchor_y="center")
    l.draw()
    w.flip()
    pyglet.clock.tick()
--8<-------------------------------------------------------------

I know I shouldn't be creating labels in the loop, but this test case was
extracted from a larger application that runs for several hours, and
creates a number of labels during its execution. Currently, the application
dies after 2 hours from memory exhaustion, when it should run for 8 hours
straight.

The memory leak remains even if I move the creation of the Label outside of
the loop, and change one of the font attributes in the loop (font name,
size, bold or italic). If I only change the text, there is no memory leak.

I tried using HeapPy to find the leaked objects, but it consistently
returns a constant memory usage, so this is really leaked memory, not
object accumulation (e.g. in a cache).

As a workaround, I ended up caching and re-using Label objects by font, so
that the font is never changed on a once-created Label. This reduced the
leak to a minimum. There still is some leakage, but it is acceptable for my
application, and could be due to a completely different cause.

Original issue reported on code.google.com by remy.bl...@pobox.com on 29 Mar 2010 at 6:38

GoogleCodeExporter commented 9 years ago
(For more info and discussion, see the recent thread in pyglet-users with 
subject
"Memory leak in text.Label".)

Original comment by ores...@gmail.com on 29 Mar 2010 at 4:42

GoogleCodeExporter commented 9 years ago
I wrote the following script in pyglet 1.2 style to try to reproduce this 
problem:

#!/usr/bin/env python

import pyglet
import string, random

random.seed()
w = pyglet.window.Window()

@w.event
def on_draw():
    w.clear()
    w.l.draw()

def change_label(dt):
    random_letters = "".join([random.choice(string.ascii_letters) for x in range(3)])
    w.l = pyglet.text.Label(random_letters, font_size=w.height/2,
                          x=w.width/2, y=w.height/2,
                          anchor_x="center", anchor_y="center")
change_label(None)
pyglet.clock.schedule(change_label)
pyglet.app.run()

== Testing Setup ==

Pyglet on all Operating Systems: 1.2dev from the repository current to today.

OS X 10.8.3: I can't duplicate any memory leakage.
Ubuntu 12.04 64-bit:  I can't duplicate any memory leakage.
Ubuntu 12.04 32-bit:  I can't duplicate any memory leakage.
CentOS 6.4 64-bit:  I can't duplicate any memory leakage.

Windows XP: According to Windows Task Manager memory leaks at about 200k-300k 
per second.
Windows 7: Leaks similar to WinXP.  If anything, it seems to leak even faster 
(though that could just be my Windows 7 running faster)

So, I've confirmed this bug exists and appears to affect Pyglet on Windows 
only.  So, I'm betting the bug lies in the windows-specific pyglet files...

Original comment by nathan.s...@gmail.com on 5 May 2013 at 6:03

GoogleCodeExporter commented 9 years ago
FWIW, I can't reproduce this with Pyglet 1.2a1 on Windows 8 with nvidia or RDP 
drivers. 

Original comment by cjgoh...@gmail.com on 5 May 2013 at 8:06

GoogleCodeExporter commented 9 years ago
Interesting.  I'm using Windows XP & 7 through VMWare fusion.

I spent several hours reading through the *win32* files in pyglet, and tried 
tweaking several things, but nothing I tried had any noticeable effect (except 
for the things I tried that crashed).

I tried lowering the RAM settings on my VMs and running my leak program until 
it crashed.  The traceback didn't seem too useful to me (it could be a red 
herring, it's just the python call that crashed when we finally ran out of 
memory), but here they are anyway:

By setting my Windows XP 32-bit VM to 352MB RAM and running my leak test script 
for about 15-20 minutes:

$ python leak-test.py
Traceback (most recent call last):
  File "leak-test.py", line 21, in <module>
    pyglet.app.run()
  File "c:\Python\lib\site-packages\pyglet\app\__init__.py", line 123, in run
    event_loop.run()
  File "c:\Python\lib\site-packages\pyglet\app\base.py", line 135, in run
    self._run_estimated()
  File "c:\Python\lib\site-packages\pyglet\app\base.py", line 164, in _run_estim
ated
    timeout = self.idle()
  File "c:\Python\lib\site-packages\pyglet\app\base.py", line 273, in idle
    redraw_all = self.clock.call_scheduled_functions(dt)
  File "c:\Python\lib\site-packages\pyglet\clock.py", line 300, in call_schedule
d_functions
    item.func(dt, *item.args, **item.kwargs)
  File "leak-test.py", line 17, in change_label
    anchor_x="center", anchor_y="center")
  File "c:\Python\lib\site-packages\pyglet\text\__init__.py", line 433, in __ini
t__
    multiline, dpi, batch, group)
  File "c:\Python\lib\site-packages\pyglet\text\__init__.py", line 257, in __ini
t__
    dpi=dpi, batch=batch, group=group)
  File "c:\Python\lib\site-packages\pyglet\text\layout.py", line 791, in __init_
_
    self.document = document
  File "c:\Python\lib\site-packages\pyglet\text\layout.py", line 874, in _set_do
cument
    self._init_document()
  File "c:\Python\lib\site-packages\pyglet\text\layout.py", line 977, in _init_d
ocument
    self._update()
  File "c:\Python\lib\site-packages\pyglet\text\layout.py", line 926, in _update

    line.start, line.boxes, context)
  File "c:\Python\lib\site-packages\pyglet\text\layout.py", line 1400, in _creat
e_vertex_lists
    box.place(self, i, x, y, context)
  File "c:\Python\lib\site-packages\pyglet\text\layout.py", line 360, in place
    ('c4B/dynamic', colors))
  File "c:\Python\lib\site-packages\pyglet\graphics\__init__.py", line 354, in a
dd
    domain = self._get_domain(False, mode, group, formats)
  File "c:\Python\lib\site-packages\pyglet\graphics\__init__.py", line 441, in _
get_domain
    domain = vertexdomain.create_domain(*formats)
  File "c:\Python\lib\site-packages\pyglet\graphics\vertexdomain.py", line 135,
in create_domain
    return VertexDomain(attribute_usages)
  File "c:\Python\lib\site-packages\pyglet\graphics\vertexdomain.py", line 186,
in __init__
    usage=usage, vbo=vbo)
  File "c:\Python\lib\site-packages\pyglet\graphics\vertexbuffer.py", line 116,
in create_mappable_buffer
    return MappableVertexBufferObject(size, target, usage)
  File "c:\Python\lib\site-packages\pyglet\graphics\vertexbuffer.py", line 382,
in __init__
    super(MappableVertexBufferObject, self).__init__(size, target, usage)
  File "c:\Python\lib\site-packages\pyglet\graphics\vertexbuffer.py", line 303,
in __init__
    glBindBuffer(target, self.id)
  File "c:\Python\lib\site-packages\pyglet\gl\lib_wgl.py", line 82, in __call__
    return self.func(*args, **kwargs)
WindowsError: [Error -1073741801] Windows Error 0xC0000017
Exception AttributeError: "'VertexDomain' object has no attribute 'attributes'"
in <bound method VertexDomain.__del__ of <VertexDomain@98f4fb0 allocs=[]>> ignor
ed

I set my Windows 7 VM to 900MB RAM and running the leak-test for nearly an hour 
before it ran out of memory and just paused.  That was a very disappointing end 
to a long wait.  I don't feel like doing it again.

Original comment by nathan.s...@gmail.com on 5 May 2013 at 10:57

GoogleCodeExporter commented 9 years ago
I can't reproduce the problem in Linux but can this be related to garbage 
collector?

I had this problem in Windows: 
http://code.google.com/p/pyglet/issues/detail?id=636

Adding a gc.collect() call before exiting fixed the problem.

Can you test the script I'm attaching to this ticket?

If it solves the problem I don't know who should run the garbage collector; I 
don't like the idea of pyglet doing it as it may have a performance hit (the 
test script uses 2x CPU with the collect call), so may be you can run it when 
it isn't a problem for your application and it's OK to free memory.

Original comment by useboxnet on 17 Jul 2013 at 4:56

Attachments:

GoogleCodeExporter commented 9 years ago
windows xp sp3, python 2.6.5, integrated gpu nvidia gforce 6150SE
Tried the Nathan script in #2, no leak: in 30 minutes process memory always 
around 31.3MB, occasional dips to 30MB, never above 32MB

pyglet 1.2alpha1, also last from repo default ( changeset:   2769:b210ac020f01 
, 2013 07 21 )

Original comment by ccanepacc@gmail.com on 7 Aug 2013 at 8:40

GoogleCodeExporter commented 9 years ago

Original comment by useboxnet on 21 Sep 2013 at 9:54

GoogleCodeExporter commented 9 years ago
gc.disable() + gc.get_count() to measure impact? 
http://docs.python.org/2/library/gc

weakref to fix? 
http://stackoverflow.com/questions/1507566/how-and-when-to-appropriately-use-wea
kref-in-python

Original comment by techtonik@gmail.com on 22 Sep 2013 at 2:13