所以问题是,我有一个函数可以让你在渲染器中显示文本,我在一个项目中实现了它,后来我想测试这个项目以防止可能的内存泄漏和宾果游戏!
经过一段时间的研究,它来自这个著名的显示文本的功能......
所以我做了一个小例子:
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
void renderText(SDL_Renderer* renderer, const char* text, int const size, const SDL_Rect text_rect, const SDL_Color text_color)
{
#ifdef __linux__
const char* font_path = "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf";
#elif _WIN32
const char* font_path = "C:\\Windows\\Fonts\\Arial.ttf";
#endif
TTF_Font* font = TTF_OpenFont(font_path, size);
if (!font) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_ttf - %s", TTF_GetError()); return; }
SDL_Surface* text_surface = TTF_RenderText_Blended(font, text, text_color);
SDL_Texture* text_texture = SDL_CreateTextureFromSurface(renderer, text_surface);
if (text_color.a!=255) SDL_SetTextureAlphaMod(text_texture, text_color.a);
SDL_RenderCopy(renderer, text_texture, NULL, &text_rect);
SDL_DestroyTexture(text_texture);
SDL_FreeSurface(text_surface);
TTF_CloseFont(font);
}
int main(int argc, char** argv)
{
//(void)argc; (void)argv;
SDL_Init(SDL_INIT_VIDEO);
TTF_Init();
SDL_Window* win = SDL_CreateWindow("Example for memory leak with SDL2_ttf", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, 0);
SDL_Renderer* ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED);
SDL_Event event;
SDL_bool running = SDL_TRUE;
while (running)
{
while (SDL_PollEvent(&event))
{
running = event.type != SDL_QUIT;
}
renderText(ren, "Hi devs !", 22, (SDL_Rect){ (640-128)/2, (480-64)/2, 128, 64 }, (SDL_Color){ 255, 255, 255, 255 });
SDL_RenderPresent(ren);
}
SDL_DestroyRenderer(ren);
SDL_DestroyWindow(win);
TTF_Quit();
SDL_Quit();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
Valgrind 告诉我:
==79266== LEAK SUMMARY:
==79266== definitely lost: 504 bytes in 1 blocks
==79266== indirectly lost: 43,152 bytes in 235 blocks
==79266== possibly lost: 8,496 bytes in 44 blocks
==79266== still reachable: 274,261 bytes in 3,422 blocks
==79266== suppressed: 0 bytes in 0 blocks
Run Code Online (Sandbox Code Playgroud)
它从哪里来?
更新1:我尝试在主循环之外初始化字体,但结果完全相同,除了提到“间接丢失”,但总是有504字节的“明确丢失”
编辑:重做测试,“更新 1”的结果与以前相同,我一定是太早关闭了窗口。
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
void renderText(SDL_Renderer* renderer, const char* text, TTF_Font* font, const int size, const SDL_Rect text_rect, const SDL_Color text_color)
{
SDL_Surface* text_surface = TTF_RenderText_Blended(font, text, text_color);
SDL_Texture* text_texture = SDL_CreateTextureFromSurface(renderer, text_surface);
if (text_color.a!=255)
SDL_SetTextureAlphaMod(text_texture, text_color.a);
SDL_RenderCopy(renderer, text_texture, NULL, &text_rect);
SDL_DestroyTexture(text_texture);
SDL_FreeSurface(text_surface);
}
int main(int argc, char** argv)
{
/* Init SDL */
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* win = SDL_CreateWindow("Example for memory leak with SDL2_ttf", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, 0);
SDL_Renderer* ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED);
SDL_Event event;
/* Init TTF */
TTF_Init();
#ifdef __linux__
const char* font_path = "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf";
#elif _WIN32
const char* font_path = "C:\\Windows\\Fonts\\Arial.ttf";
#endif
TTF_Font* font = TTF_OpenFont(font_path, 22);
if (!font)
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_ttf - %s", TTF_GetError());
return -1;
}
/* Main loop */
SDL_bool running = SDL_TRUE;
while (running)
{
while (SDL_PollEvent(&event))
{
running = event.type != SDL_QUIT;
}
renderText(ren, "Hi devs !", font, 22, (SDL_Rect){ (640-128)/2, (480-64)/2, 128, 64 }, (SDL_Color){ 255, 255, 255, 255 });
SDL_RenderPresent(ren);
}
TTF_CloseFont(font);
SDL_DestroyRenderer(ren);
SDL_DestroyWindow(win);
TTF_Quit();
SDL_Quit();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
==18309== LEAK SUMMARY:
==18309== definitely lost: 504 bytes in 1 blocks
==18309== indirectly lost: 160 bytes in 1 blocks
==18309== possibly lost: 65,728 bytes in 367 blocks
==18309== still reachable: 274,261 bytes in 3,422 blocks
==18309== suppressed: 0 bytes in 0 blocks
Run Code Online (Sandbox Code Playgroud)
使用 Valgrind 进行第二次测试,与之前相同:
==22622== definitely lost: 504 bytes in 1 blocks
==22622== indirectly lost: 43,152 bytes in 235 blocks
==22622== possibly lost: 21,136 bytes in 123 blocks
==22622== still reachable: 274,261 bytes in 3,422 blocks
==22622== suppressed: 0 bytes in 0 blocks
Run Code Online (Sandbox Code Playgroud)
更新2:我指定没有“renderText”函数及其显示的同一示例程序不会产生内存泄漏,并且无论使用时间或我在那里做什么,字节数都不会改变。我在另一个仅显示文本的项目中尝试过,结果与本示例相同。
无法释放的问题不在您的代码中。进一步挖掘valgrind --leak-check=full
,您会发现程序中生成分配的调用是:
==5815== by 0x400C81: main (ttf-valgrind.c:24)
Run Code Online (Sandbox Code Playgroud)
对应于:
SDL_Init(SDL_INIT_VIDEO);
Run Code Online (Sandbox Code Playgroud)
没有任何与libSDL2_ttf
释放失败有关的牵连。问题出现在libSDL2
及其与 的交互中libX11
。你无能为力。您正确清理:
TTF_CloseFont(font);
SDL_DestroyRenderer(ren);
SDL_DestroyWindow(win);
TTF_Quit();
SDL_Quit();
Run Code Online (Sandbox Code Playgroud)
虽然这对于 libSDL2 来说并不是一个很好的实践,但从技术上来说,允许在程序返回和程序退出时处理资源的释放并没有什么问题main()
。这似乎就是其中之一。
有许多库可以执行此操作,包括 Gtk。因此,在使用第三方库时,您必须对免费失败持保留态度。继续追查它,并让自己确信正在发生的事情是库依赖程序退出来处理空闲。此时您已经完成了所有您能做的事情,除非您想编写并向 SDL2 提交一个补丁来在其中一个函数中处理它xxx_Quit()
。