我的项目广泛使用SDL2-2.0.8来显示来自各种科学成像相机的数据帧。我的实际项目使用的是wxWidgets 3.1.1和SDL_CreateWindowFrom(xid),而不是SDL_CreateWindow()。
我最近开始使用AddressSanitizer来帮助调试应用程序并查找可能的内存泄漏(对于我的应用程序,Valgrind太慢了)。 AddressSanitizer已通知我我正在努力解决严重的内存泄漏。下面是一个独立的完全可编译的示例,它说明了我的问题。
#include <iostream>
#include <unistd.h>
#include <random>
#include <SDL2/SDL.h>
int main()
{
SDL_Window *window = nullptr;
SDL_Renderer* renderer = nullptr;
SDL_Texture *texture = nullptr;
uint8_t *pixels = new uint8_t[640 * 480 * 3];
// Random Numbers
std::mt19937 rng;
rng.seed(std::random_device()());
std::uniform_int_distribution<std::mt19937::result_type> random(0, 255);
int pitch;
if ((window = SDL_CreateWindow("Test", 0, 0, 640, 480, 0)) == nullptr)
{
std::cerr << SDL_GetError() << "\n";
return -1;
}
if ((renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED)) == nullptr)
{
std::cerr << SDL_GetError() << "\n";
return -1;
}
// Create the SDL Texture
if ((texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGB24, SDL_TEXTUREACCESS_STREAMING, 640, 480)) == nullptr)
{
std::cerr << SDL_GetError() << "\n";
return -1;
}
int counter = 0;
while (counter < 500)
{
SDL_LockTexture(texture, nullptr, (void**) &pixels, &pitch);
// Create greyscale noise - a bit like old television sets without an antenna
for (int n = 0; n < 640 * 480 * 3; n += 3)
{
int random_pix = random(rng);
pixels[n] = random_pix;
pixels[n + 1] = random_pix;
pixels[n + 2] = random_pix;
}
SDL_UnlockTexture(texture);
SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_RenderPresent(renderer);
counter++;
}
// If the following line is uncommented and delete [] pixels commented, then I get a double-free in SDL
//free(pixels);
SDL_DestroyTexture(texture);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
// This line causes a double-free error, if it's commented out then I get a memory leak of 921600 bytes
delete[] pixels;
atexit(SDL_Quit);
return 0;
}
SDL似乎正在尝试重新分配分配给我的像素缓冲区的内存,但失败并导致内存泄漏。有趣的是,如果我使用:
SDL_UpdateTexture(texture, NULL, pixels, m_Width * 3);
然后我可以自行分配 pixels ,以解决内存泄漏问题。有人知道发生了什么吗?这仅仅是AddressSanitizer的误报吗?
更多信息:我的项目是用C ++编写的,并在Fedora 28上使用GCC-8进行了编译。AddressSanitizer来自标准的Fedora存储库。我知道你们中许多人会认为我应该使用智能指针,但是这样做将需要对我的项目进行大量重构,而我根本没有时间这样做。
非常感谢您的阅读,我感谢您提供的任何帮助。
阿曼达
答案 0 :(得分:1)
请注意,SDL_LockTexture()
的签名采用了指向指针的指针。这表明您不应该传递自己的缓冲区。您正在泄漏,因为SDL_LockTexture()
更改了要传递的指针whos address 的值,以指向其自身的内部缓冲区,现在您不能删除(无用的)分配的缓冲区。显然,然后发生了双重释放,因为您正在删除不属于您的缓冲区,而该缓冲区在您调用SDL_DestroyTexture()
时已经释放了(可能我不确定确切的实现方式)。
还请注意,数据实际上可能不是您期望的格式。 SDL_CreateTexture()
可以随意忽略您的建议,并为您提供后端支持的“最接近”的匹配格式。您需要查询纹理的实际格式,以了解如何处理像素。
如注释中所述:如果要以自己的格式提供自己的像素,则必须使用SDL_UpdateTexture()
,但这当然会慢得多。
有关地址清理器的说明:它不会产生误报。如果它报告了问题,则说明您确实有问题。