Juce graphics command line leak


#1

Hello,

I've just created a command line program using the Introjucer.

I'm using the example code from the Doxygen documentation...


// Create a blank Image
    Image myImage (Image::RGB, 500, 500, true);
    Graphics g (myImage);
    g.setColour (Colours::red);
    g.fillEllipse (20, 20, 300, 200);  // draws a red ellipse in our image.

But I'm getting a leak....


*** Leaked objects detected: 1 instance(s) of class TypefaceCache
JUCE Assertion failure in juce_LeakedObjectDetector.h:95
*** Leaked objects detected: 1 instance(s) of class WaitableEvent
JUCE Assertion failure in juce_LeakedObjectDetector.h:95

I have literally just the above code in the program, so I'm not using a TypeFace. Is it because the Image is getting deleted before the Graphics, or do I need to do something special for command line apps graphics?

Cheers!


#2

Those objects expect the DeletedAtShutdown system to clean them up - maybe you need to use the ScopedJuceInitialiser_GUI class?


#3

Excellent, I didn't know about that!

Thanks Jules! :)


#4

So I am coming across the same memory leak issue because I’m using both and Image and a Graphics context as temporary objects in order to draw some text to an OpenGLTexture as follows:

Image image (Image::ARGB, imageWidth, imageHeight, true);
Graphics g (image);
...
g.drawText(text, xOffset, 0, imageWidth, imageHeight, just);
texture.release(); // make sure to free any previous texture memory
texture.loadImage(image);

Is there a way for the Image and Graphics objects to NOT “expect the DeletedAtShutdown system to clean them up”? I can’t come up with any other ideas to manually free whatever needs to be freed…

Thanks in advance for the help!


#5

Using temporary objects like that won’t be the reason for your leak… Hard to guess from this exactly what your real problem is, but maybe you’re not freeing your GL objects before you delete the context?


#6

Ok, thanks for the sanity check Jules! I determined that the Graphics::drawText call is causing the leak for me. For example:

Image image (Image::ARGB, imageWidth, imageHeight, true);
Graphics g (image);
int w = imageWidth/100.0;
int h = imageHeight/100.0;
int x = 0, y = 0;
const String str ("billy, bob, joe!!!");
for (int i = 0; i < 100; ++i) {
    g.drawText(str, 10, y, 100, 40, just); // This leaks
    y += 10;
    //g.drawEllipse(x, y, w, h, 1); // ...but this doesn't
    //x += w;  y += h;
}
texture.release(); // make sure to free any previous texture memory
texture.loadImage(image);

I will also mention that this section of code is getting called inside a OpenGLRenderer::renderOpenGL() so it is executing on the background GL thread, rather than the typical Component::paint()… maybe that has something to do with the leaking?

I also found out that Font::getStringWidthFloat() is leaking as well inside the same section of my code (inside a renderOpenGL() callback):

Font font (fontName, cellHeight, fontStyle);
const String str ("billy, bob, joe!!!");
float len = 0;
for (int i = 0; i < 100; ++i) {
    len += font.getStringWidthFloat(str);
}

Furthermore, I discovered that this leak is being caused by the Font::getTypeface() call because changing to:

float Font::getStringWidthFloat (const String& text) const
{
    float w = 10; //getTypeface()->getStringWidth (text);
    if (font->kerning != 0)
        w += font->kerning * text.length();
    return w * font->height * font->horizontalScale;
}

fixes the leak. I’m really at a loss as to how to fix/workaround these two leaks. I can’t find any other way to draw text with a Juce Font to a OpenGLTexture. Am I using these classes in a way they weren’t designed for? Thanks very much for the feedback!

Also, I tried putting the Graphics::drawText() and Font::getStringWidth() calls into the Component::paint() callback and they were still leaking. Is that the expected behavior? If you want to redraw correctly sized text whenever the window is resized are you stuck with having a leak?


Graphics::drawText and Font::getStringWidth leaking?
#7

Exactly what you’re doing doesn’t really matter… None of the juce objects will leak if the library’s used correctly, i.e. if all your threads shut down cleanly and if you use a ScopedJuceInitialiser_GUI or call DeletedAtShutdown::deleteAll to clean up before your app exits.