当我在游戏中加载新关卡时,我的内存泄漏。
每次调用LoadMap()函数时,我的ram会跳得更高,直到程序崩溃,如:
TileGame.exe中0x752dc42d处的未处理异常:Microsoft C ++异常:内存位置为0x003af420的std :: bad_alloc ..
...或
TileGame.exe中0x7787a30e处的未处理异常:0xC0000005:访问冲突读取位置0xfeeefef6。
我正在使用像这样的2d矢量:
//A 2D array of Tile pointers
std::vector<std::vector<Tile*>> map;
//A 2D array of Tile pointers for the background
std::vector<std::vector<Tile*>> background_map;
这是NewLevel()函数,它清除了存储游戏切片的两个地图。该函数还调用LoadMap()函数。
void Level::NewLevel(std::string filename){
//Generate a new level with Island generator.
//IslandGenerator* island = new IslandGenerator();
this->map.clear();
this->background_map.clear();
sf::Image size_image;
if (!size_image.loadFromFile("data/Levels/" + filename)){
std::cout << "failed to load image" << std::endl;
return;
}
SetDimensions(size_image.getSize().x, size_image.getSize().y);
LoadMap(filename);
}
这是我每次加载瓷砖时用来调整地图大小的函数:
void Level::SetDimensions(int w, int h)
{
this->map.resize(w);
this->background_map.resize(w);
//Each row has h columns of null Tile pointers
for(int i = 0; i < w; i++)
{
this->map.at(i).resize(h, 0);
this->background_map.at(i).resize(h,0);
}
}
最后,这是LoadMap()函数,它从图像中加载所有图块并设置它们的纹理和属性。
void Level::LoadMap(std::string filename)
{
// Loads as image to to use the .getSize() operation not allowed for textures
if (!Image_load.loadFromFile("data/Levels/" + filename))
std::cout << "failed to load image" << std::endl;
if (!background_image_load.loadFromFile("data/Levels/background_" + filename))
std::cout << "failed to load image" << std::endl;
x_load = Image_load.getSize().x;
y_load = Image_load.getSize().y;
this->level_w = x_load;
this->level_h = y_load;
player = new Player(entity_texture_manager);
AddEntity((this->screen_size_x/2)-(player->baseSprite.getLocalBounds().width/2), (this->screen_size_y/2)-(player->baseSprite.getLocalBounds().height/2), player);
// -----------------------------------------------------------------------
Tile* new_tile = new Tile();
Tile* new_background_tile = new Tile();
for(int ii = 0; ii < y_load; ii++)
{
for(int jj = 0; jj < x_load; jj++)
{
try
{
new_tile = new Tile();
new_background_tile = new Tile();
}
catch (std::bad_alloc& ba)
{
std::cerr << "bad_alloc caught: " << ba.what() << '\n';
return;
}
//new_tile = new Tile();
//new_background_tile = new Tile();
color_load = Image_load.getPixel (jj, ii);
// Get the background pixels
background_color_load = background_image_load.getPixel(jj,ii);
// Background-----------------------------------------
if((int)background_color_load.r == 128 && (int)background_color_load.g == 0){
new_background_tile->setTexture(texture_manager.getTexture(11));
new_background_tile->color = 11;
new_background_tile->type = 0;
new_background_tile->light_blocking_amount = 20;
}
else
{
new_background_tile->setTexture(texture_manager.getTexture(2));
new_background_tile->color = 2;
new_background_tile->type = 0;
new_background_tile->light_blocking_amount = 20;
}
// ---------------------------------------------------
if((int)color_load.r == 255 && (int)color_load.g == 255){
new_tile->setTexture(texture_manager.getTexture(3));
new_tile->color = 3;
new_tile->type = 1;
}
//grass1
else if((int)color_load.r == 0 && (int)color_load.g == 128 && (int)color_load.b == 128){
new_tile->setTexture(texture_manager.getTexture(10));
new_tile->color = 10;
new_tile->type = 0;
}
else if((int)color_load.r == 0 && (int)color_load.g == 128 && (int)color_load.b == 255){
new_tile->setTexture(texture_manager.getTexture(12));
new_tile->color = 12;
new_tile->type = 0;
}
else if((int)color_load.r == 0 && (int)color_load.g == 100 && (int)color_load.b == 128){
new_tile->setTexture(texture_manager.getTexture(13));
new_tile->color = 13;
new_tile->type = 0;
}
else if((int)color_load.r == 255){
new_tile->setTexture(texture_manager.getTexture(1));
new_tile->color = 1;
new_tile->type = 1;
}
else if((int)color_load.g == 255){
new_tile->setTexture(texture_manager.getTexture(0));
new_tile->color = 0;
new_tile->type = 1;
}
else if((int)color_load.b == 255){
new_tile->setTexture(texture_manager.getTexture(2));
new_tile->color = 2;
new_tile->type = 0;
}
// brick
else if((int)color_load.g == 128 && (int)color_load.b == 128 && (int)color_load.r == 128){
new_tile->setTexture(texture_manager.getTexture(9));
new_tile->color = 9;
new_tile->type = 1;
}
// sand
else if((int)color_load.r == 128){
new_tile->setTexture(texture_manager.getTexture(7));
new_tile->color = 7;
new_tile->type = 1;
}
else if((int)color_load.g == 128){
new_tile->setTexture(texture_manager.getTexture(8));
new_tile->color = 8;
new_tile->type = 1;
}
else{
new_tile->setTexture(texture_manager.getTexture(0));
new_tile->color = 0;
new_tile->type = 1;
}
//Adds the specified tile to the 2D array
//cout << map.size() << endl;
map[jj][ii] = 0;
background_map[jj][ii] = 0;
AddTile(jj, ii, new_tile);
AddBackgroundTile(jj, ii, new_background_tile);
/*
//------Ouput Method---------
for (int r=0; r < map.size(); r++)
{
for (int c=0; c < map[r].size(); c++)
cout << map[r][c] << '/t';
cout << endl;
}
*/
}
}
}
更新
感谢您的评论。我添加了一个删除我的Tile对象的函数,但这似乎仍无效。
我现在称这个功能。
void Level::CleanUp(){
for(int ii = 0; ii < this->map.size(); ii++){
for(int jj = 0; jj < this->h; jj++){
delete &this->map[ii][jj];
delete &this->background_map[ii][jj];
}
}
this->map.clear();
this->background_map.clear();
}
我做错了什么想法?
更新2:
这是我的瓷砖类:
class Tile
{
public:
int type;
int color;
int light_level;
int light_blocking_amount;
int loc_x, loc_y;
int LightRadius;
int LightLevel;
Tile();
~Tile();
sf::Sprite baseSprite;
void Draw(int x, int y, sf::RenderWindow* rw);
void setTexture(sf::Texture& texture);
};
更新3:
sprite类是一个内置的sfml类:
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2014 Laurent Gomila (laurent.gom@gmail.com)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
#ifndef SFML_SPRITE_HPP
#define SFML_SPRITE_HPP
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Graphics/Export.hpp>
#include <SFML/Graphics/Drawable.hpp>
#include <SFML/Graphics/Transformable.hpp>
#include <SFML/Graphics/Vertex.hpp>
#include <SFML/Graphics/Rect.hpp>
namespace sf
{
class Texture;
////////////////////////////////////////////////////////////
/// \brief Drawable representation of a texture, with its
/// own transformations, color, etc.
///
////////////////////////////////////////////////////////////
class SFML_GRAPHICS_API Sprite : public Drawable, public Transformable
{
public :
////////////////////////////////////////////////////////////
/// \brief Default constructor
///
/// Creates an empty sprite with no source texture.
///
////////////////////////////////////////////////////////////
Sprite();
////////////////////////////////////////////////////////////
/// \brief Construct the sprite from a source texture
///
/// \param texture Source texture
///
/// \see setTexture
///
////////////////////////////////////////////////////////////
explicit Sprite(const Texture& texture);
////////////////////////////////////////////////////////////
/// \brief Construct the sprite from a sub-rectangle of a source texture
///
/// \param texture Source texture
/// \param rectangle Sub-rectangle of the texture to assign to the sprite
///
/// \see setTexture, setTextureRect
///
////////////////////////////////////////////////////////////
Sprite(const Texture& texture, const IntRect& rectangle);
////////////////////////////////////////////////////////////
/// \brief Change the source texture of the sprite
///
/// The \a texture argument refers to a texture that must
/// exist as long as the sprite uses it. Indeed, the sprite
/// doesn't store its own copy of the texture, but rather keeps
/// a pointer to the one that you passed to this function.
/// If the source texture is destroyed and the sprite tries to
/// use it, the behaviour is undefined.
/// If \a resetRect is true, the TextureRect property of
/// the sprite is automatically adjusted to the size of the new
/// texture. If it is false, the texture rect is left unchanged.
///
/// \param texture New texture
/// \param resetRect Should the texture rect be reset to the size of the new texture?
///
/// \see getTexture, setTextureRect
///
////////////////////////////////////////////////////////////
void setTexture(const Texture& texture, bool resetRect = false);
////////////////////////////////////////////////////////////
/// \brief Set the sub-rectangle of the texture that the sprite will display
///
/// The texture rect is useful when you don't want to display
/// the whole texture, but rather a part of it.
/// By default, the texture rect covers the entire texture.
///
/// \param rectangle Rectangle defining the region of the texture to display
///
/// \see getTextureRect, setTexture
///
////////////////////////////////////////////////////////////
void setTextureRect(const IntRect& rectangle);
////////////////////////////////////////////////////////////
/// \brief Set the global color of the sprite
///
/// This color is modulated (multiplied) with the sprite's
/// texture. It can be used to colorize the sprite, or change
/// its global opacity.
/// By default, the sprite's color is opaque white.
///
/// \param color New color of the sprite
///
/// \see getColor
///
////////////////////////////////////////////////////////////
void setColor(const Color& color);
////////////////////////////////////////////////////////////
/// \brief Get the source texture of the sprite
///
/// If the sprite has no source texture, a NULL pointer is returned.
/// The returned pointer is const, which means that you can't
/// modify the texture when you retrieve it with this function.
///
/// \return Pointer to the sprite's texture
///
/// \see setTexture
///
////////////////////////////////////////////////////////////
const Texture* getTexture() const;
////////////////////////////////////////////////////////////
/// \brief Get the sub-rectangle of the texture displayed by the sprite
///
/// \return Texture rectangle of the sprite
///
/// \see setTextureRect
///
////////////////////////////////////////////////////////////
const IntRect& getTextureRect() const;
////////////////////////////////////////////////////////////
/// \brief Get the global color of the sprite
///
/// \return Global color of the sprite
///
/// \see setColor
///
////////////////////////////////////////////////////////////
const Color& getColor() const;
////////////////////////////////////////////////////////////
/// \brief Get the local bounding rectangle of the entity
///
/// The returned rectangle is in local coordinates, which means
/// that it ignores the transformations (translation, rotation,
/// scale, ...) that are applied to the entity.
/// In other words, this function returns the bounds of the
/// entity in the entity's coordinate system.
///
/// \return Local bounding rectangle of the entity
///
////////////////////////////////////////////////////////////
FloatRect getLocalBounds() const;
////////////////////////////////////////////////////////////
/// \brief Get the global bounding rectangle of the entity
///
/// The returned rectangle is in global coordinates, which means
/// that it takes in account the transformations (translation,
/// rotation, scale, ...) that are applied to the entity.
/// In other words, this function returns the bounds of the
/// sprite in the global 2D world's coordinate system.
///
/// \return Global bounding rectangle of the entity
///
////////////////////////////////////////////////////////////
FloatRect getGlobalBounds() const;
private :
////////////////////////////////////////////////////////////
/// \brief Draw the sprite to a render target
///
/// \param target Render target to draw to
/// \param states Current render states
///
////////////////////////////////////////////////////////////
virtual void draw(RenderTarget& target, RenderStates states) const;
////////////////////////////////////////////////////////////
/// \brief Update the vertices' positions
///
////////////////////////////////////////////////////////////
void updatePositions();
////////////////////////////////////////////////////////////
/// \brief Update the vertices' texture coordinates
///
////////////////////////////////////////////////////////////
void updateTexCoords();
////////////////////////////////////////////////////////////
// Member data
////////////////////////////////////////////////////////////
Vertex m_vertices[4]; ///< Vertices defining the sprite's geometry
const Texture* m_texture; ///< Texture of the sprite
IntRect m_textureRect; ///< Rectangle defining the area of the source texture to display
};
} // namespace sf
#endif // SFML_SPRITE_HPP
////////////////////////////////////////////////////////////
/// \class sf::Sprite
/// \ingroup graphics
///
/// sf::Sprite is a drawable class that allows to easily display
/// a texture (or a part of it) on a render target.
///
/// It inherits all the functions from sf::Transformable:
/// position, rotation, scale, origin. It also adds sprite-specific
/// properties such as the texture to use, the part of it to display,
/// and some convenience functions to change the overall color of the
/// sprite, or to get its bounding rectangle.
///
/// sf::Sprite works in combination with the sf::Texture class, which
/// loads and provides the pixel data of a given texture.
///
/// The separation of sf::Sprite and sf::Texture allows more flexibility
/// and better performances: indeed a sf::Texture is a heavy resource,
/// and any operation on it is slow (often too slow for real-time
/// applications). On the other side, a sf::Sprite is a lightweight
/// object which can use the pixel data of a sf::Texture and draw
/// it with its own transformation/color/blending attributes.
///
/// It is important to note that the sf::Sprite instance doesn't
/// copy the texture that it uses, it only keeps a reference to it.
/// Thus, a sf::Texture must not be destroyed while it is
/// used by a sf::Sprite (i.e. never write a function that
/// uses a local sf::Texture instance for creating a sprite).
///
/// See also the note on coordinates and undistorted rendering in sf::Transformable.
///
/// Usage example:
/// \code
/// // Declare and load a texture
/// sf::Texture texture;
/// texture.loadFromFile("texture.png");
///
/// // Create a sprite
/// sf::Sprite sprite;
/// sprite.setTexture(texture);
/// sprite.setTextureRect(sf::IntRect(10, 10, 50, 30));
/// sprite.setColor(sf::Color(255, 255, 255, 200));
/// sprite.setPosition(100, 25);
///
/// // Draw it
/// window.draw(sprite);
/// \endcode
///
/// \see sf::Texture, sf::Transformable
///
////////////////////////////////////////////////////////////
答案 0 :(得分:1)
您不会删除旧的Tile对象。它们被定义为指针,因此您需要在清除background_map和map之前手动删除它们。
实际上,我根本没有看到任何删除声明。
答案 1 :(得分:1)
根据您发布的信息,我的建议是以这种方式更改您的Tile类,以减轻内存泄漏:
#include <memory>
class Tile
{
public:
int type;
int color;
int light_level;
int light_blocking_amount;
int loc_x, loc_y;
int LightRadius;
int LightLevel;
std::shared_ptr<sf::Sprite> baseSprite;
Tile();
//... other member functions
//
};
Sprite
课程有点复杂,我不知道它是否可以按原样复制(你可以编写一个小测试应用程序来查看Sprite是否是[安全]可复制)。因此,为了安全起见,将其创建为智能指针,并在Tile
的构造函数上实例化它。
然后我会用这个:
std::vector<Tile>
而不是
std::vector<Tile*>
构建Tile时,您正在构造一个新的Sprite对象:
Tile::Tile() : baseSprite(new sf::Sprite)
{
// whatever else
}
现在Tile类可以用作对象。需要注意的是确保您在shared_ptr中没有循环(阅读shared_ptr使用和循环)。但是根据你发布的代码,我认为不会有,但你应该检查一下。
执行此操作后,将不再需要Tile
析构函数,因为shared_ptr将在删除最后一次引用时删除。
答案 2 :(得分:0)
1
的第一个循环会立即导致内存泄漏,因为0
分配的内存不会被删除。
Tile* new_tile = new Tile(); // <-- 0
Tile* new_background_tile = new Tile(); // <-- 0
for(int ii = 0; ii < y_load; ii++)
{
for(int jj = 0; jj < x_load; jj++)
{
try
{
new_tile = new Tile(); // <--- 1
new_background_tile = new Tile(); // <--- 1
}