You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SDL2程序运行时内存占用持续增长问题排查及优化

问题根因

内存逐帧暴涨和你用SDL_Surface还是SDL_Texture没有直接关系,核心是资源重复创建后从未释放,属于典型内存泄漏:

  • 主循环内的switch(hand)分支每一帧都会执行:你每帧都调用IMG_Load重新加载手持物品图片、调用TTF_RenderText_Solid重新生成文字表面,但旧的handitem和text表面占用的内存从来没有被释放,每帧都会泄漏对应体积的内存,短时间冲到2G完全符合这个泄漏的表现。
  • 删除已放置物体时,你只把table数组的占位标记设为false,从未调用SDL_FreeSurface释放对应格子tableTexture存储的表面,这部分内存也会持续泄漏。
  • 程序退出前你也没有释放提前加载的背景、字体等资源,不过这部分是退出时才会触发的泄漏,不是运行时内存逐帧上涨的原因。
换成SDL_Texture能否解决问题?

不能直接解决。
如果换成SDL_Texture之后你还是保持现在“每帧重复创建资源、不释放旧资源”的写法,内存照样会泄漏,甚至因为显卡显存资源未及时释放,内存上涨速度可能更快。SDL_Texture搭配硬件渲染确实能提升渲染效率,但它解决的是渲染性能问题,修复不了你忘记释放资源导致的内存泄漏。

正确修复方案

SDL资源管理的核心原则很简单:加载一次全程复用,谁创建谁释放,资源不用立刻销毁,按这个原则改代码就行:

  • 所有固定不变的资源(背景图、5个物品图、字体)全部提到主循环外,程序启动时只加载一次,全程复用,绝对不要放在主循环里反复读磁盘加载。
  • 切换手持物品时,不要每帧都重新加载图片、渲染文字,只在hand变量的值真的发生变化时,先调用SDL_FreeSurface释放旧的handitem和text表面,再赋值/生成新的对应资源。
  • 删除格子上的物体时,先调用SDL_FreeSurface释放tableTexture[placex][placey]指向的表面,再把占位标记设为false。
  • 程序退出前,把所有创建过的表面、字体、窗口等资源,逐个调用对应销毁函数(SDL_FreeSurface/TTF_CloseFont/SDL_DestroyWindow)释放,最后再调用SDL_Quit/IMG_Quit/TTF_Quit退出对应子系统。

核心修改的参考代码片段:

// 主循环外提前加载所有物品表面,存到数组全程复用,避免重复读盘
SDL_Surface* itemSurfaces[6] = {
    nullptr,
    IMG_Load("item1.png"),
    IMG_Load("item2.png"),
    IMG_Load("item3.png"),
    IMG_Load("item4.png"),
    IMG_Load("item5.png")
};
const char* itemNames[6] = {"", "House", "Road1", "Road2", "Junction", "Park"};

// 主循环内只在hand值变化时才更新手持物品和提示文字
int lastHand = hand;
if (keyState[SDL_SCANCODE_1]) hand = 1;
if (keyState[SDL_SCANCODE_2]) hand = 2;
if (keyState[SDL_SCANCODE_3]) hand = 3;
if (keyState[SDL_SCANCODE_4]) hand = 4;
if (keyState[SDL_SCANCODE_5]) hand = 5;
if (hand != lastHand) {
    SDL_FreeSurface(handitem);
    SDL_FreeSurface(text);
    handitem = itemSurfaces[hand]; // 直接复用预加载的表面,无需重新加载
    char textBuf[64];
    snprintf(textBuf, sizeof(textBuf), "Selected item: %s", itemNames[hand]);
    text = TTF_RenderText_Solid(Sans, textBuf, White);
}

删除物体的逻辑补全释放操作:

if (remove) {
    placex = mousex / 40;
    placey = mousey / 40;
    if (table[placex][placey]) {
        SDL_FreeSurface(tableTexture[placex][placey]); // 先释放表面
        tableTexture[placex][placey] = nullptr;
        table[placex][placey] = false; // 再改占位标记
    }
}

放置物体时也不需要每次调用IMG_Load,直接从预加载的itemSurfaces数组里取对应指针赋值给tableTexture即可,既省了重复读盘的开销,也不会重复创建表面造成泄漏。

如果后续你要切换到SDL_Texture做硬件加速渲染,资源管理逻辑完全一致:创建纹理用SDL_CreateTextureFromSurface,不用时调用SDL_DestroyTexture释放即可,不要每帧重复创建纹理。


内容的提问来源于stack exchange,提问作者László Lipódi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 17:45:38