-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Calling sf::Text::setOutlineThickness()
in a loop allocates a lot of memory (0.5 GB)
#1823
Comments
I tried to reproduce it with VS 2019, latest SFML master (commit eeeda74), Windows x64 Debug mode. Could not see the behavior your experienced; memory stayed around ~36 MB and maybe 2-3 MB less with the Did you set up a fresh project for this? Any other special configuration? |
Yes I made a completely fresh setup. I downloaded latest 2.5.1 (Visual C++ 15 (2017) - 64-bit version, linked and set include path, added the dlls and added arial.ttf, I added a Project.zip in the post. |
Changing the outline thickness, as well as changing any other visual properties, will trigger a recalculation of the geometry, which means that every glyph needs to be repositioned etc. This involves some The clear & append call shouldn't cause additional allocations, but I guess that's largely dependent on the STL implementation. Have you tried this in release mode? |
And out of interest, does it behave like this even if you don't set any text? Asking because we have // No text: nothing to draw
if (m_string.isEmpty())
return; in the middle |
Leaving the text empty will not cause the behavior. I found In Text.cpp removing line 501 |
Unless I am misunderstanding the code, the culprit seems to be const Glyph& Font::getGlyph(Uint32 codePoint, unsigned int characterSize, bool bold, float outlineThickness) const
{
// Get the page corresponding to the character size
GlyphTable& glyphs = m_pages[characterSize].glyphs;
// Build the key by combining the glyph index (based on code point), bold flag, and outline thickness
Uint64 key = combine(outlineThickness, bold, FT_Get_Char_Index(static_cast<FT_Face>(m_face), codePoint));
// Search the glyph into the cache
if (auto it = glyphs.find(key); it != glyphs.end())
{
// Found: just return it
return it->second;
}
else
{
// Not found: we have to load it
Glyph glyph = loadGlyph(codePoint, characterSize, bold, outlineThickness);
return glyphs.emplace(key, glyph).first->second;
}
} The Why does the glyph depend on |
It's this code in SFML/src/SFML/Graphics/Font.cpp Lines 607 to 613 in 3579ecb
So the cause of this issue is that for different outline thicknesses (and characters, character sizes, bold styles), separate glyphs are allocated. This is normally expected, because the user will use those glyphs to display text, and wants them to remain cached for fast rendering. Now, the problem is that we never deallocate them. So cycling through many possible combinations of glyphs will cause lots of allocations, and memory that stays reserved. And the allocation pattern depends massively on the application:
So unfortunately there's no easy way to garbage-collect glyphs. A possible strategy might be a LRU cache with a fixed size, but that will kill performance for applications that need more than the cache size simultaneously. Maybe exposing a tweakable strategy in the @DanielRabl could you tell us more about the project that made you notice this in the first place? (I.e. not the reproducible example) |
I wanted to make a animation, where text is highlighted by a big outline thickness that vanishes quickly. Initially I reduced the outline thickness, after seeing the memory consumption I now instead just reduce the alpha value. It does make sense to me now why this memory is not cleared, but like I said therefore it's maybe worth warning about this behavior in the description of setOutlineThickness. |
So you started with a wide outline, and continuously made it narrower? Can you tell us roughly how many steps those were?
Yes, that's the least. Even better would be if we could enable workflows like yours 🙂 |
It was starting with a outline thickness of 2, and when the animation starts, it interpolates the value down to 0 every frame (144 frames / second) in the span of 1 second. For interpolation I used a curve slope ( |
sf::Text::setOutlineThickness()
in a loop allocates a lot of memory (0.5 GB)
I had a lot more memory consumption than I should have had recently, so I went through every step and figured that calling
sf::Text::setOutlineThickness()
(thereforesf::Text::ensureGeometryUpdate()
) in a loop with different values allocates a lot of memory (process memory reached about 550 megabytes after 10 seconds and stays there):Environment is Windows 10, Visual Studio 2019 (16.9.6).
SFML version is 2.5.1 (Visual C++ 15 (2017) - 64-bit).
Build settings are Debug, x64, /std:c++latest.
Here is the visual studio project folder using the latest version on the sfml-dev.org side SFMLBug.zip.
and here's the project using a CMake build of the latest commit: SFMLBug_commit_eeeda74.zip
This example should reproduce the behavior. Any font should work here (as I tried a few), here I used Arial font.
I do realize that calling
setOutlineThickness
this way is probably wrong as it's quite an expensive maneuver, however I don't expect there to be so much allocations. There should probably be a warning on the comment tosetOutlineThickness
if this memory problem is not to be solved.Thanks!
The text was updated successfully, but these errors were encountered: