SDL2 的内存泄漏

Big*_*t71 2 c sdl-ttf sdl-2

所以问题是,我有一个函数可以让你在渲染器中显示文本,我在一个项目中实现了它,后来我想测试这个项目以防止可能的内存泄漏和宾果游戏!

经过一段时间的研究,它来自这个著名的显示文本的功能......

所以我做了一个小例子:

#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”函数及其显示的同一示例程序不会产生内存泄漏,并且无论使用时间或我在那里做什么,字节数都不会改变。我在另一个仅显示文本的项目中尝试过,结果与本示例相同。

Dav*_*ica 5

无法释放的问题不在您的代码中。进一步挖掘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()