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

如何修复Raylib C++中生成商品地图时的内存泄漏函数?

内存泄漏与Double Free问题排查解决

我正在学习C++,用raylib基于Perlin Noise制作地图,需要为每种商品生成独立地图展示其可用省份,但运行时内存占用过高。用-fsanitizer检测后,定位到问题出在以下函数:

void renderGoodMap(World* w, Texture2D* tex) {
  vector<Good> g = w->getGoods();
  int cols = w->get_num_cols();
  int rows = w->get_num_rows();

  for (uint i = 0; i < g.size(); i++) {
    byte* pixels = new byte[ rows * cols * 4 ];
    bool* map = w->getGoodMapById(i);
    for (int j = 0; j < rows * cols; j++) {
      int index = j * 4;
      if (map[ j ]) {
        pixels[ index + 0 ] = (byte)255;
        pixels[ index + 1 ] = (byte)0;
        pixels[ index + 2 ] = (byte)0;
        pixels[ index + 3 ] = (byte)150;
      }
      else {
        pixels[ index + 0 ] = (byte)255;
        pixels[ index + 1 ] = (byte)255;
        pixels[ index + 2 ] = (byte)255;
        pixels[ index + 3 ] = (byte)100;
      }
    }
    Image img = {
      .data = pixels,
      .width = cols,
      .height = rows,
      .mipmaps = 1,
      .format = 7
    };
    ImageResizeNN(&img, cols * TILESIZE, rows * TILESIZE);
    tex[ i ] = LoadTextureFromImage(img);
    delete img.data;
  }
}

我尝试用delete img.data释放内存,但如果同时删除pixels数组会触发double free错误,目前正在学习智能指针,想搞清楚问题根源和解决办法。


问题根源

  1. Double Free错误原因:ImageResizeNN函数会重新分配内存存储缩放后的图像数据,并且会自动释放原img.data指向的内存(也就是你用new创建的pixels数组)。之后你再调用delete img.data,等于对已经被raylib释放的内存再次执行释放操作,直接触发double free。
  2. 内存占用过高原因:循环中每次new的像素数组,如果没被正确释放,会造成内存泄漏;另外LoadTextureFromImage会把图像数据复制到GPU显存,但CPU端的图像数据如果没清理,也会持续占用内存。

解决方法

1. 停止手动释放img.data或pixels

raylib的图像操作函数会自行管理原图像数据的内存,不需要手动调用delete。

2. 用raylib官方函数释放图像内存

加载纹理后,必须调用UnloadImage来释放CPU端的图像数据,而不是手动delete,这是raylib内存管理的规范。

3. 用智能指针优化内存管理(可选)

用std::unique_ptr自动管理pixels数组的内存,避免因忘记释放或异常导致的泄漏,同时也能更安全地转移指针所有权。

修改后的代码:

#include <memory>

void renderGoodMap(World* w, Texture2D* tex) {
  vector<Good> g = w->getGoods();
  int cols = w->get_num_cols();
  int rows = w->get_num_rows();

  for (uint i = 0; i < g.size(); i++) {
    // 用unique_ptr自动管理像素数组,避免手动new/delete出错
    std::unique_ptr<byte[]> pixels = std::make_unique<byte[]>(rows * cols * 4);
    bool* map = w->getGoodMapById(i);
    
    for (int j = 0; j < rows * cols; j++) {
      int index = j * 4;
      if (map[j]) {
        pixels[index + 0] = static_cast<byte>(255);
        pixels[index + 1] = static_cast<byte>(0);
        pixels[index + 2] = static_cast<byte>(0);
        pixels[index + 3] = static_cast<byte>(150);
      } else {
        pixels[index + 0] = static_cast<byte>(255);
        pixels[index + 1] = static_cast<byte>(255);
        pixels[index + 2] = static_cast<byte>(255);
        pixels[index + 3] = static_cast<byte>(100);
      }
    }

    Image img = {
      .data = pixels.release(), // 将指针所有权转移给Image
      .width = cols,
      .height = rows,
      .mipmaps = 1,
      .format = 7
    };

    ImageResizeNN(&img, cols * TILESIZE, rows * TILESIZE);
    tex[i] = LoadTextureFromImage(img);
    UnloadImage(img); // 用raylib函数释放所有CPU端图像内存
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 04:05:44