SDL2程序触发OOM被杀 帧循环重复加载图片问题排查修复
SDL2 2D程序运行时内存持续上涨触发OOM问题
问题复现代码
#include"global.h" #include"tools/entity.h" #include"tools/input.c" static const int width = 800; static const int height = 600; int main (int argc, char **argv) { SDL_Init(SDL_INIT_VIDEO); int init = IMG_Init(IMG_INIT_PNG); if((init & IMG_INIT_PNG) != IMG_INIT_PNG) { printf("Couldnt load images :P"); } // 创建窗口 SDL_Window *window = SDL_CreateWindow("Ferengine",SDL_WINDOWPOS_UNDEFINED,SDL_WINDOWPOS_UNDEFINED,width,height,SDL_WINDOW_SHOWN); // 创建渲染器 SDL_Renderer *renderer = SDL_CreateRenderer(window,-1,SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); // SDL_Surface * image = IMG_Load("funnyman.png"); // if(!image) { printf("Could not load image because : %s\n",IMG_GetError()); } // SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, image); // 渲染设置 /* SDL_SetRenderDrawColor(renderer,255,0,0,255); SDL_SetWindowOpacity(window,1.0f); */ entity2D player; player.posx = 0; player.posy = 0; player.sprite = "funnyman.png"; int speed = 100; // 主循环标记 bool running = true; SDL_Event event; while(running) { while(SDL_PollEvent(&event)) { if(event.type == SDL_QUIT) { running = false; } } SDL_RenderClear(renderer); // SDL_RenderCopy(renderer, texture, NULL, NULL); drawImage("funnyman.png",renderer,10,10,100,100); drawEntity(player,renderer,100,100); switch(getKeyPressed()) { case SDLK_w: player.posy += 1 * speed; break; case SDLK_s: player.posy -= 1 * speed; break; case SDLK_d: player.posx += 1 * speed; break; case SDLK_a: player.posx -= 1 * speed; break; case SDLK_q: running = false; default: break; } SDL_RenderPresent(renderer); } // 释放资源 IMG_Quit(); SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); SDL_Quit(); return 0; }
说明:代码中
getKeyPressed()为自定义封装函数,返回int类型(SDL_Keycode底层本质为int类型),程序使用的编译命令为gcc -o Build/Ferengine Source/main.c -lSDL2 -lSDL2_image -ldl
问题现象
程序启动后角色移动逻辑可正常运行,但静置一段时间后窗口会自动关闭,触发*OOM(Out of Memory,内存不足)*错误,进程被系统强制杀死。
根因分析
问题核心出在渲染阶段的资源加载逻辑:
- 主循环每帧执行时都会调用
drawImage和drawEntity两个绘制函数,两个函数内部每次调用都会重新从磁盘加载图片文件、创建对应的SDL_Surface和SDL_Texture资源 - 每次创建的临时纹理、表面资源使用完成后没有调用对应销毁接口释放,造成持续性内存泄漏
- 程序开启了垂直同步,会以匹配显示器刷新率的频率(通常每秒60次)重复加载资源、泄漏内存,即使用户不做任何操作,内存占用也会持续上涨,最终耗尽系统可用资源触发OOM。
修复方案
- 所有需要重复使用的图片、纹理资源,统一在进入主循环前完成预加载,将生成的
SDL_Texture*缓存起来,不要在渲染循环内做磁盘IO和重复的资源创建操作 - 渲染阶段直接读取预加载好的纹理资源,调用
SDL_RenderCopy完成绘制,避免无意义的资源开销 - 程序退出阶段,先销毁所有预加载的纹理资源,再按顺序销毁渲染器、窗口,最后退出SDL子系统,避免退出阶段的资源泄漏。
内容的提问来源于stack exchange,提问作者wij
相关产品推荐
相关产品推荐

