Memory Leak with SDL Multiline Text
Posted: Tue Aug 13, 2013 9:54 am
*********
The Next Generation of 2D Roleplaying Games
http://elysianshadows.com/phpBB3/
You include the header, run the program, and check the output window for any reported leaks. It obviously won't catch everything but it's pretty damn useful.Visual Leak Detector is a free, robust, open-source memory leak detection system for Visual C++.
It's pretty easy to use. After installing it, you just need to tell Visual C++ where to find the included header and library file.
Then it can be used with any C/C++ project simply by adding the following line to your code:
#include <vld.h>
When you run your program under the Visual Studio debugger, Visual Leak Detector will output a memory leak report at the end of your debugging session. The leak report includes the full call stack showing how any leaked memory blocks were allocated. Double-click on a line in the call stack to jump to that file and line in the editor window.
It's a very effective way to quickly diagnose, and fix, memory leaks in C/C++ applications.
This is the correct thing to do.jmcintyretech wrote:First I added the line that frees the SDL surface before starting the next loop. The program runs fine but the memory issue still occurs.
This is invalid. std::basic_string::c_str() returns a pointer to a C string that is owned by the basic_string. This pointer is typically the string, which the basic_string acts upon, although this isn't guaranteed by the standard. The pointer is valid until the basic_string is modified (ie, a non-const method is called, with a few exceptions) or destructed. You do not own the string and should not concern yourself with its deletion. If you allocate before_newline_char using new char, you are allocating one byte of memory and then immediately losing the pointer by overwriting it with the pointer given to you by c_str(). Thus, the call to delete acts upon the pointer owned by basic_string. The basic_string class still behaves as if the pointer is valid and likely attempts to delete it upon destruction, resulting in a crash due to double-freeing memory.jmcintyretech wrote:Next I tried declaring the const char* that I pass to the SDL_RenderText_Solid function as:const char* before_newline_char = new char;rather than:const char*;and then deleting it on each loop to free up the memory:delete before_newline_char;This completely crashes the program.
I hope you're joking. You are joking right? If this is truly your mindset I sincerely hope you never develop software I have to use. This is like a car manufacturer saying, "Well, the airbags don't work but the rest of the car is fine. How many people ever actually use the airbags anyway?"jmcintyretech wrote: 3. The leak is small and probably insignificant. I think at this point there is not much I can do to remedy it. Also, the leak only seems to occur when I switch between the main menu of the game and the level that draws the text. Unless somebody goes back and forth 100 times while playing the game it probably won't cause a serious leak.
Just so you know, most people I've talked to about the SDL TTF stuff have always just opted to create a png with all the characters and just blit the characters they need onto a surface. It seems to be the way to go, and that's what I do anymore. But yeah, don't just leave that leak in and keep using that function, it will only get worse.jmcintyretech wrote:Gotcha dandymcgee. Believe me I don't want to have that kind of mindset. I just meant that the bug seems to be in SDL and there is not much I can do to fix it on my own. At any rate I will TRY to fix it!
The last thing I want to do is write shitty, memory leaking software
Yup, if the leak is party of a 3rd party library and you can't contact the developers to have it fixed, your solution is to stop using that library. Just because your include leaking code in your program doesn't excuse you from the fact that your software now leaks.eatcomics wrote:Just so you know, most people I've talked to about the SDL TTF stuff have always just opted to create a png with all the characters and just blit the characters they need onto a surface. It seems to be the way to go, and that's what I do anymore. But yeah, don't just leave that leak in and keep using that function, it will only get worse.jmcintyretech wrote:Gotcha dandymcgee. Believe me I don't want to have that kind of mindset. I just meant that the bug seems to be in SDL and there is not much I can do to fix it on my own. At any rate I will TRY to fix it!
The last thing I want to do is write shitty, memory leaking software
My main complaint with this method is that, by using bitmap fonts, you lose scalability and virtually all of the kerning and metric information from FreeType. Writing an efficient font renderer using FreeType directly with OpenGL is trivial, gives good results, and can be altered to perform more advanced text drawing, such as extruded 3D glyphs, smooth scaling of glyph outlines, etc.eatcomics wrote:Just so you know, most people I've talked to about the SDL TTF stuff have always just opted to create a png with all the characters and just blit the characters they need onto a surface. It seems to be the way to go, and that's what I do anymore. But yeah, don't just leave that leak in and keep using that function, it will only get worse.
SDL_Surface* generate_text(TTF_Font* font, SDL_Color color, std::string text) { std::size_t len = text.size(); std::vector<SDL_Surface*> lines; int width = 0; int height = 0; for (std::size_t off = 0; off != std::string::npos;) { std::size_t next_off = text.find("\n"); if (next_off != std::string::npos) { text[next_off] = '\0'; ++next_off; if (next_off >= len) next_off = std::string::npos; } SDL_Surface* line = TTF_RenderText_Solid(font, &text[off], color); if (line) { if (line->w > width) width = line->w; height += line->h; } lines.push_back(line); off = next_off; } if (lines.empty()) return SDL_CreateRGBSurface(SDL_SWSURFACE, 0, 0, 24, 0, 0, 0, 0); SDL_Surface* surface = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 24, 0, 0, 0, 0); SDL_SetColorKey(surface, SDL_SRCCOLORKEY, 0); if (surface) { SDL_Rect dstrect = {0}; std::vector<SDL_Surface*>::const_iterator it = lines.begin(); std::vector<SDL_Surface*>::const_iterator end = lines.end(); while (it != end) { SDL_Surface* line = *it; SDL_BlitSurface(line, NULL, surface, &dstrect); dstrect.y += line->h; SDL_FreeSurface(line); // clean up as we go ++it; } } return surface; } class main_menu { public: main_menu() { static SDL_Color color = {0xFF, 0xFF, 0xFF}; font = TTF_OpenFont("Arial.ttf", 32); text_surface = generate_text(font, color, "New Game\nLoad Game\nOptions\nQuit"); text_off.x = (screen->w - text_surface->w) / 2; text_off.y = (screen->h - text_surface->h) / 2; } ~main_menu() { SDL_FreeSurface(text_surface); TTF_CloseFont(font); } void draw() { SDL_BlitSurface(text_surface, NULL, screen, &text_off); } private: TTF_Font* font; SDL_Rect text_off; SDL_Surface* text_surface; };
There may be some other libraries for SDL that will let you use TTFs, but you'd have to look around. I agree with Nokurn, it is annoying that the most widely suggested TTF extension doesn't work, but usually people don't need all that TTF offers for an SDL project. But if someone would, I would say Nokurn's SDL solution is the way to go, if you can't find another library to use in conjunction with SDL.jmcintyretech wrote:VLD reports no problems with my code. Apparently the problem does lie within SDL_ttf. I will look into using OpenGL or using SDL in some other way.Code: Select all
No memory leaks detected. Visual Leak Detector is now exiting. The program '[1384] Terminal_Fantasy.exe: Native' has exited with code 0 (0x0).