memory leak

Our development efforts are being stymied by an apparent resource leak in pyglet.text. Run the following, and watch your memory consumption soar:
import random
import gc
from pyglet import window, clock, text
from pyglet.gl import *

w = window.Window()
l = text.Label("", font_size=w.height, x=w.width/2, y=w.height/2, halign="center", valign="center")
f = clock.ClockDisplay()

while not w.has_exit:
    w.dispatch_events()
    w.clear()
    l.text = "".join(map(lambda x: random.choice("abcdef"), xrange(3)))
    l.draw()
    f.draw()
    w.flip()
    gc.collect()
    clock.tick()

(log in to comment)

Comments

Yep. It looks like you're using pyglet 1.1 which is `alpha'. You guys should report a bug on this since your code is concise and to the point (try pyglet mailing list). Or better yet, patch pyglet and submit your patch ;) If you don't want to downgrade, there is an obvious workaround (depending on the complexity of your real use case) - I'll leave this as an exercise to the reader.

Cheerio - back to tearing the flesh off of my worthless competitors.

We'd really like to see this "obvious workaround" - everything we've tried exhibits the same memory leak (or possibly a different memory leak, hard to tell).
Also, we can't downgrade - pyglet 1.0 doesn't work on at least one of our development machines.
Martin: Make a list of labels up front to choose from instead resetting the text. If you want a large pool - your load time will suck, of course - but you could put it in a thread and have the UI display `Loading'. 25 or less loads in an almost tolerable amount of time on my machine. The other option is just to instantiate a new Label each loop - load time will not suck, but your framerate will take a serious hit. Either way - no memory leak.

Good luck.

Unfortunately that doesn't work for anyone using labels to display scores, times or any kind of more complex dynamically calculated information. Your second suggestion also leaks memory, albeit more slowly than resetting the text on the existing label.
Why not just use pyglet.font.Text instead? We've used pyglet.font.Text for all our OSD stuff - FPS for debugging, interactive terminal, scores, etc.
pyglet.font.Text is implemented in terms of pyglet.text.Label, so the leak is the same.

I see it is in pyglet 1.1 - it wasn't in 1.0.

It's easy to just make assumptions about code, but its better to back them up with experiments. From my experiments, resetting text on pyglet.font.Text does not leak (testing on TRUNK) - contrary to your assumption. This could be explained by side effects on setting text inside Font - many other curious things occur, notably:

self._layout.begin_update()
...
self._layout.end_update()
Although we never produced a simple specimen for it, we definitely encountered memory leaks when using pyglet.font.Text; in fact, we only discovered and switched to using pyglet.text.Label in the hope that it might fix the error (plus setting width on a pyglet.font.Text doesn't work in 1.1, although it looks like it would be a fairly easy fix).
The leak is due to the font object being recreated every frame, but the Batch is holding onto the old groups that used the previous incarnation. The only reason the font object is being recreated all the time is the gc.collect(), which flushes the font cache. Removing this removes the memory leak.

I've managed to trace most references of group in batch, but there's still one left, so I haven't been able to fix it completely yet. In a "real-life" program this should not be (as much of a) a problem. If it is, manually hold onto the font references yourself (using pyglet.font.load).

adam: I haven't received a bug report about width on Text.

alex: Thanks! That seems to have fixed it. Using Pyglet 1.1 is proving difficult but probably ultimately rewarding. :-) I believe the 'width' problem was that it wasn't a valid keyword arg to pyglet.text.Label, although it worked for me. Not sure... If we come across any more bugs (or potential bugs) we'll be sure to let you know.
Am I the only one who doesn't want a White Dress?
Am I the only one who doesn't want a White Dress?