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

SDL2如何实现图片仅单次加载 避免内存泄漏按需显示

问题根源

你的代码出现内存泄漏是三个核心错误导致的:

  • C语言函数参数为值传递,你在Display_nosignal函数内部给Scene指针赋值,修改的只是函数栈上的局部副本,不会改变外部传入的指针实际值。因此每次调用函数时Scene == NULL的判断永远成立,会反复执行IMG_LoadTexture创建新纹理,旧纹理既没有被复用也没有被销毁,持续占用内存造成泄漏。
  • 你把资源加载逻辑放在了逐帧调用的渲染函数中,本身就违反了SDL资源管理的基本原则:纹理等GPU资源应该在初始化阶段统一加载,渲染阶段只做绘制调用,退出阶段统一销毁。
  • 额外逻辑错误:原代码中SDL_SetRenderTarget(Rendu, Scene);属于API误用,IMG_LoadTexture加载的纹理默认是静态不可绘制的,不能作为渲染目标使用,这行代码会直接触发SDL运行错误,需要删除。
可行实现方案

整体按照「初始化预加载-渲染时仅绘制-退出时统一销毁」的逻辑改造即可,完全避免重复加载问题。

1. 初始化阶段预加载所有常驻纹理

在SDL渲染器创建完成后、进入游戏主循环之前,把电视需要用到的无信号图、枪击场景图全部加载到内存,纹理指针统一存储(可以放在全局变量,也可以放在自定义的游戏状态结构体中,避免散落在各个渲染函数里)。

// 纹理指针统一存储,示例用全局变量,实际项目建议放到游戏上下文结构体中
SDL_Texture* tex_tv_nosignal = NULL;
SDL_Texture* tex_tv_shoot = NULL;

// 初始化阶段调用,传入已经创建完成的渲染器
int LoadTVTextures(SDL_Renderer* Rendu)
{
    tex_tv_nosignal = IMG_LoadTexture(Rendu, "mages/No_Signal.jpg");
    if (tex_tv_nosignal == NULL) {
        printf("加载无信号纹理失败: %s\n", SDL_GetError());
        return -1;
    }

    // 后续要切换的枪击场景也在此处提前加载
    tex_tv_shoot = IMG_LoadTexture(Rendu, "mages/shoot_scene.jpg");
    if (tex_tv_shoot == NULL) {
        printf("加载枪击场景纹理失败: %s\n", SDL_GetError());
        return -1;
    }
    return 0;
}

2. 渲染函数仅负责绘制,不处理资源加载

渲染函数只接收已经加载完成的纹理指针,执行拷贝绘制逻辑即可,不要在函数内做任何资源创建、销毁操作。切换电视显示内容时,只需要更换传入的纹理指针,没有任何重复加载开销。

// 传入当前要显示的电视纹理、渲染器、电视屏幕在窗口上的目标区域
void DrawTVScreen(SDL_Texture* current_tv_tex, SDL_Renderer* Rendu, const SDL_Rect* dest_rect)
{
    // 仅做绘制,无资源操作
    SDL_RenderCopy(Rendu, current_tv_tex, NULL, dest_rect);
}
  • 常态显示时传入tex_tv_nosignal即可,需要切换到枪击场景时直接传入预加载好的tex_tv_shoot,切换过程无IO、无内存分配。

3. 程序退出时统一销毁资源

在游戏退出流程中、SDL渲染器销毁之前,统一释放所有预加载的纹理,避免退出时的资源泄漏。

void UnloadTVTextures()
{
    if (tex_tv_nosignal != NULL) {
        SDL_DestroyTexture(tex_tv_nosignal);
        tex_tv_nosignal = NULL;
    }
    if (tex_tv_shoot != NULL) {
        SDL_DestroyTexture(tex_tv_shoot);
        tex_tv_shoot = NULL;
    }
}
注意事项
  • 绝对不要在逐帧执行的主循环逻辑中调用IMG_LoadTexture、SDL_CreateTexture这类资源创建接口,不仅会造成内存泄漏,磁盘IO和GPU资源创建的开销还会导致严重的帧率卡顿。
  • 如果后续需要新增更多电视播放的画面,统一在初始化加载阶段加入即可,切换逻辑不需要修改。
  • 只有通过SDL_CreateTexture创建时指定了SDL_TEXTUREACCESS_TARGET标志的纹理,才能作为SDL_SetRenderTarget的目标使用,外部加载的图片纹理不要做此操作。

内容的提问来源于stack exchange,提问作者dMight

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 03:03:27