我的记忆不是免费的
My memory is not free'd
我有一个相当大的程序,它通常运行得很好,但运行起来需要大量的内存。这是一种机器学习方法,可以收集大量数据,因此这通常是可以的,但即使在收集了所有数据之后,内存也会增长得非常快,所以我使用valgrind massif来找出问题所在。massif堆树的顶部看起来像这样:
99.52% (60,066,179B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
->43.50% (26,256,000B) 0x439785: Image::Image(SDL_Surface*) (Image.cpp:95)
| ->43.50% (26,256,000B) 0x437277: EncodedFeature::forwardPass() (EncodedFeature.cpp:65)
....
所以我想,嗯,也许构建的图像不是免费的,但不是:
void EncodedFeature::forwardPass()
{
// Get image:
Image* img = new Image(screen);
// Preprocess:
if(preprocessor)
preprocessor->process(img);
// Do forward pass:
encoder->encode(img, features);
delete img;
}
图像构造函数:
Image::Image(SDL_Surface* surface)
{
this->width = surface->w;
this->height = surface->h;
pixels = new int*[width];
for(int i = 0; i < width; i++)
pixels[i] = new int[height];
for(int x = 0; x < surface->w; x++)
for(int y = 0; y < surface->h; y++)
pixels[x][y] = getPixelFromSDLSurface(surface, x, y);
}
只分配一个稍后在析构函数中释放的像素数组:
Image::~Image()
{
if(!pixels)
return;
for(int x = 0 ; x < width; x++)
delete[] pixels[x];
delete[] pixels;
}
最后一个罪魁祸首:
Uint32 Image::getPixelFromSDLSurface(SDL_Surface *surface, int x, int y)
{
if(!surface)
return 0;
// Got this method from http://www.libsdl.org/cgi/docwiki.fcg/Pixel_Access
int bpp = surface->format->BytesPerPixel;
/* Here p is the address to the pixel we want to retrieve */
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
switch(bpp) {
case 1:
return *p;
break;
case 2:
return *(Uint16 *)p;
break;
case 3:
if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
return p[0] << 16 | p[1] << 8 | p[2];
else
return p[0] | p[1] << 8 | p[2] << 16;
break;
case 4:
return *(Uint32 *)p;
break;
default:
return 0; /* shouldn't happen, but avoids warnings */
}
}
正如评论中提到的,我是从SDL维基上得到的,所以我希望那里没有任何泄漏。在我的例子中,bpp实际上总是1,所以它只返回地址p处的int,这对我来说听起来并不泄漏
我在这里已经无计可施了。有人能想到记忆去了哪里吗?我的意思是,massif特别指向Image构造函数,但我看不出有什么错误。。。
非常感谢你关注我的问题!
最大
回答您的意见:
你是对的,我不需要img作为指针。我有Java背景,所以我只想让一切都成为指针:)改变了它,但没有帮助。
第95行在构造函数的第一个for循环中:pixels[i] = new int[height];
在其中一个预处理器中,我会调整图像的大小,但我会调用重置函数来执行此操作,该函数应确保删除旧数组:
void Image::reset(int width, int height)
{
if(pixels)
{
// Delete old image:
for(int x = 0 ; x < width; x++)
delete[] pixels[x];
delete[] pixels;
}
this->width = width;
this->height = height;
pixels = new int*[width];
for(int i = 0; i < width; i++)
pixels[i] = new int[height];
}
之后我重新填充像素值。。。
任何地方都没有抛出异常。
你建议我在哪里使用智能指针?
谢谢你的回答!
我认为您在图像类中没有正确表示像素。我认为您可以使用正确无符号类型的简单一维vector
(uint32_t
?)。
(在标题中):
class Image {
protected:
std::vector<uint32_t> pixels;
...
};
(在实施文件中)
size_t Image::offset(unsigned x, unsigned y) {
return (y * width) + x;
}
Image::Image(const SDL_Surface* surface)
{
width = surface->w;
height = surface->h;
pixels.reserve(width * height);
for(unsigned x = 0; x < width; x++)
for(unsigned y = 0; y < height; y++)
pixels[offset(x, y)] = getPixelFromSDLSurface(surface, x, y);
}
然后你的析构函数将完全为空,因为它没有任何作用:
Image::~Image() {
}
请注意,您需要使用offset()
方法为任何给定的x/y对获取vector
的正确索引。
最有可能的情况是,在某些代码路径中没有调用重置或析构函数,从而泄漏内存。
幸运的是,C++具有防止此类泄漏的内置功能:它被称为vector
。
因此,首先你让你的pixels
看起来像这样:
typedef std::vector<int> PixelCol;
typedef std::vector<PixelCol> Pixels;
Pixels pixels;
现在我们在构造函数中对其进行大小调整:
Image::Image(SDL_Surface* surface)
: pixels(surface->w, PixelCol(surface->h))
{
this->width = surface->w;
this->height = surface->h;
for(int x = 0; x < surface->w; x++)
for(int y = 0; y < surface->h; y++)
pixels[x][y] = getPixelFromSDLSurface(surface, x, y);
}
最后我们更新了reset
:
void Image::reset(int width, int height)
{
Pixels(width, PixelCol(height)).swap(pixels);
}
通过让该语言管理您的内存,您可以完全消除代码中的任何此类内存管理错误。
- 我的神经网络不起作用 [XOR 问题]
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 我的字符计数代码计算错误.为什么
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- cmake在我的项目中所需的所有静态库都不成功
- 为什么我的代码在输出中增加了93天
- 我的简单if-else语句是如何无法访问的代码
- 为什么我的for循环不能正确获取argv
- 我的项目不会像"undefined reference to `grpc::g_core_codegen_interface'"那样使用未定义的引用错误进行编译
- 我找不到瓦尔格林德告诉我的记忆链接
- 我的记忆动态规划算法有什么问题?
- 瓦尔格林德:我的记忆泄漏在哪里
- 我的记忆是怎么回事?
- 我的记忆泄漏在哪里
- 为什么这个循环会破坏我的记忆
- 是使用我的物理记忆增强managed_mapped_file
- 我的记忆不是免费的
- 在我的应用程序中可以免费使用VCL或MFC吗
- 我地图上的记忆问题在哪里?
- 如何为队列释放内存?我的不免费