我正在用C ++制作我的第一个游戏,似乎我有内存泄漏。
Stack Exchange不会让我发布图片,但我将任务管理器打开到“Memory”选项卡,当我的游戏打开时内存图慢慢增加,然后在游戏关闭时突然减少。
现在,我的游戏中只包含一个可以移动并射击子弹的球,并使用SDL_ttf显示文本以显示剩余的弹药数量,选择的是哪支枪,以及我所在的波形,这是一个静态变量来自主类。然而,奇怪的是,即使没有射击任何子弹或按下任何按钮,这种内存泄漏仍然会发生。自从我开始游戏以来,我一直在确保自己没有任何内存泄漏,直到最近还没有任何内存泄漏。这意味着我的内存泄漏很可能是由显示的文本或访问静态变量引起的,因为我不确切知道前向声明是如何工作的(我不认为)。
由于在没有按下游戏中的任何按钮的情况下发生内存泄漏,我认为它必须在游戏循环中触发,所以我检查了所有函数调用和游戏循环中的所有内容,这使我认为它必须来自Player类中的某些东西,特别是在Update()或renderHUD()中。
这是来自Player和Main类的代码,我包含了标题,以确保我的前向声明是正确的,所以你看到我正在使用哪些指针。我没有包含游戏循环,因为已经包含了可能导致内存泄漏的所有函数调用。我正在使用带有SDL2的Visual Studio 2012。
#pragma once
#include "GameObject.h"
#include "Bullet.h"
#include "destructive_reasoning.h"
#include "Screen.h"
#include "Magazine.h"
#include <SDL_ttf.h>
#include <sstream>
class Main;
class Player : public GameObject
{
public:
private:
int* xOffset;
int* yOffset;
int gameWidth;
int gameHeight;
Screen* screen;
SDL_Renderer* renderer;
std::vector<Bullet*> bullets;
std::vector<Magazine> clips;
std::vector<std::string> weaponNames;
bool readyToShoot;
Weapon weapon;
TTF_Font* font;
SDL_Color fg;
std::stringstream s;
SDL_Surface* ammoSurface;
SDL_Texture* ammoText;
SDL_Rect ammoRect;
SDL_Surface* weaponSurface;
SDL_Texture* weaponText;
SDL_Rect weaponRect;
//SDL_Surface* killedSurface;
//SDL_Texture* killedText;
//SDL_Rect killedRect;
SDL_Surface* waveSurface;
SDL_Texture* waveText;
SDL_Rect waveRect;
};
void Player::Update()
{
move();
for(unsigned int c = 0; c < bullets.size(); c++)
{
bullets[c]->Update();
bullets[c]->Render();
if(bullets[c]->getAge() >= bullets[c]->getRange())
{
//Bullet* temp = bullets[c];
bullets.erase(bullets.begin() + c);
//delete temp;
}
}
renderHUD();
}
void Player::Render(int _xOffset, int _yOffset)
{
sprite->getRectByReference()->x = int(x);
sprite->getRectByReference()->y = int(y);
sprite->draw(int(x),int(y),_xOffset,_yOffset);
}
void Player::renderHUD()
{
s.str(std::string());
s.clear();
s << *clips[weapon].getAmmo();
ammoRect.w = s.str().size() * 32;
ammoSurface = TTF_RenderText_Solid(font,s.str().c_str(),fg);
ammoText = SDL_CreateTextureFromSurface(renderer,ammoSurface);
SDL_RenderCopy(renderer,ammoText,NULL,&ammoRect);
s.str(std::string());
s.clear();
s << weaponNames[weapon];
weaponRect.w = s.str().size() * 16;
weaponSurface = TTF_RenderText_Solid(font,s.str().c_str(),fg);
weaponText = SDL_CreateTextureFromSurface(renderer,weaponSurface);
SDL_RenderCopy(renderer,weaponText,NULL,&weaponRect);
s.str(std::string());
s.clear();
s << "Wave: " << Main::wave;
waveRect.w = s.str().size() * 16;
waveSurface = TTF_RenderText_Solid(font,s.str().c_str(),fg);
waveRect.x = gameWidth - waveRect.w;
waveText = SDL_CreateTextureFromSurface(renderer,waveSurface);
SDL_RenderCopy(renderer,waveText,NULL,&waveRect);
}
Player::~Player(void)
{
//delete xOffset --- Not Deleting because it is a passed pointer, this variable is used in other classes;
//delete yOffset --- "" ;
//delete sprite; --- Not deleting because when deleted, I get a Access violation reading location 0xFEEEFEEE.;
//I don't mind not deleting this because there is only one instance of this class, and I don't think
//this is what's causing the memory leak
//delete screen; --- Not deleting this because screen is used by most other classes, and is deleted in my main class
for(unsigned int c = 0; c < bullets.size(); c++)
{
delete bullets[c];
}
TTF_CloseFont(font);
SDL_FreeSurface(ammoSurface);
SDL_DestroyTexture(ammoText);
SDL_FreeSurface(weaponSurface);
SDL_DestroyTexture(weaponText);
//SDL_FreeSurface(killedSurface); ---I commented out every line of code involving this surface, it doesn't actually exist
//SDL_DestroyTexture(killedText); ---I commented out every line of code involving this texture, it doesn't actually exist
SDL_FreeSurface(waveSurface);
SDL_DestroyTexture(waveText);
TTF_Quit();
}
#pragma once
#include "destructive_reasoning.h"
#include "Screen.h"
#include "Sprite.h"
#include "Player.h"
class Main
{
...
}
答案 0 :(得分:2)
使用SDL_Surfaces
创建SDL_Texture
后,您需要释放void Player::renderHUD()
{
// ...
ammoSurface = TTF_RenderText_Solid(font,s.str().c_str(),fg);
ammoText = SDL_CreateTextureFromSurface(renderer,ammoSurface);
SDL_RenderCopy(renderer,ammoText,NULL,&ammoRect);
// Your prbolem is here, ammoSurface needs to be freed since it's already been copied into ammoText
// Calling FreeSurface on ammoSurface will free it, but ammoText reamins intact
SDL_FreeSurface(ammoSurface);
// ....
}
。
TTF_RenderText_Solid()
是的,每次使用{{1}}
时都会这样答案 1 :(得分:1)
我想我会把我的评论变成答案。
在你的代码中你打电话
ammoSurface = TTF_RenderText_Solid(font,s.str().c_str(),fg);
ammoText = SDL_CreateTextureFromSurface(renderer,ammoSurface);
...
weaponSurface = TTF_RenderText_Solid(font,s.str().c_str(),fg);
weaponText = SDL_CreateTextureFromSurface(renderer,weaponSurface);
和
waveSurface = TTF_RenderText_Solid(font,s.str().c_str(),fg);
waveRect.x = gameWidth - waveRect.w;
waveText = SDL_CreateTextureFromSurface(renderer,waveSurface)
每一帧,我都会从那里删除它们,在渲染循环中初始化它们,在更新函数中更新它们并简单地将它们作为参数传递给渲染循环,你将失去内存泄漏:原因是您将只为每个实例创建一个内存实例,然后您可以根据需要重复使用它们。
作为一般规则,尝试而不是创建/销毁渲染循环中的任何对象,往往会变得大而乱。重复使用将节省大量的ram和周期。
我会拥有lastAmmo
,lastWave
,lastWeapon
个变量,这些变量保存每个变量的前一个值,这样您就可以在更新循环中引用值并仅生成新的纹理如果值已更改,则每个仅。这样,当你进入渲染循环时,你只需要一些静态渲染代码来运行整个节目。
虽然可以使用CRT进行调试以追踪内存泄漏,但我建议Visual Leak Detector:很好,直接并且集成到Visual Studio 2008,2010和2012中。
希望这有帮助,如果不让我知道,我可以添加或修改以满足您的需求:)