Glyph Memory Allocation


#1

Hi all,

I've been experimenting with drawing in to a cached Image on my own Thread to keep complicated draw routines off the Message Thread, and I have discovered some strange memory behaviour in the OSXTypeface.  Just to note that I'm seeing this using the tip of the Juce repo.

 

When drawing in to a Graphics object generated on a Thread which isn't the Message Thread (i.e. not one handed to the Component::paint() method), I am seeing constant allocation of memory stacking up over time in the OSXTypeface::getGlyphPositions method.

To be clear, this is NOT a memory leak. The memory is all freed correctly when the app is closed.

 

The problem appears only when I use one of the text drawing methods of the Graphics object.

 

Below is the simplest way to recreate the issue, simply place this in to a GUI App and attach Instruments (look for __NSDictionaryl):

MainContentComponent::MainContentComponent()
    : m_Image(Image::ARGB, 600, 400, true)
    , m_Lock()
{
    setSize (600, 400);

    // Start the timer which will repaint the Image.
    Timer::startTimer(20);

    // Start the timer which will actually draw the Image.
    HighResolutionTimer::startTimer(20);

}

MainContentComponent::~MainContentComponent()
{
    Timer::stopTimer();
    HighResolutionTimer::stopTimer();
}

void MainContentComponent::paint (Graphics& g)
{
    ScopedLock lock(m_Lock);

    // Here, we just draw the Image which has been drawn in to elsewhere.
    g.drawImageAt(m_Image, 0, 0);
}

void MainContentComponent::timerCallback()
{
    // Ensure that all calls to repaint()/paint() happen on proper Thread.
    repaint();
}

void MainContentComponent::hiResTimerCallback()
{
    ScopedLock lock(m_Lock);

    // Here, we are creating a temporary Graphics context and drawing some text into it.
    Graphics g(m_Image);    

    g.fillAll (Colour (0xff001F36));

    g.setFont (Font (16.0f));
    g.setColour (Colours::white);
    g.drawText ("Hello World!", getLocalBounds(), Justification::centred, true);
}

 

There is a screenshot here: http://postimg.org/image/ug5pul53b/  which shows the increasing memory allocation, etc.
 


drawText at paint callback of OpenGLAppComponent
#2

Hi LukeM,

I was able to reproduce your bug, however, I cannot find anything wrong with the JUCE code. The function causing the memory increase is CTLineCreateWithAttributedString which seems to be retaining the NSString which refers to the attribute's name. As far as I can tell it's never released. There are a few posts on stack overflow complaining about similar problems. Does anybody have a workaround for this? Sorry that I don't have any better news for you :-(.

Fabian


#3

Hi Fabian,

Thanks for reply; that is indeed not good news!

 

However, I have discovered that setting JUCE_CORETEXT_AVAILABLE to 0 makes the problem go away. Is there any reason I shouldn't be doing this?

 

Thanks again,

Luke.


#4

See line 1025 of juce_mac_Fonts.mm which is the fallback when CoreText is not available (or when JUCE_CORETEXT_AVAILABLE is 0). For example, getOutlineForGlyph won't work on iOS (see the return false) and uses a hack on OS X where it draws the glyph into a bezier path and then tries to interpret the bezier path. I haven't tested the performance but wouldn't be surprised if this workaround is many times slower than using CoreText.