Jump to content
  • Advertisement
Sign in to follow this  
JWindebank

Memory Leak - Help please?

This topic is 4728 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi guys, I'm still trying my hand at some very begginer game making, and after following Aaron's tutorial on Game States at HERE I am having two minor problems. The first is that I have a massive memory leak somewhere, and for the life of me I cannot figure out where. I am assuming it has something to do with not clearing an SDL_Surface or something but I'm really not sure. The second is that sometimes that keyboard gets laggy. Am I doing something wrong here to cause it lag on processing the input functions? Code follows: defines.h
//------------------------------------------------------------------------------
// Project: Project Name
// File: defines.h
//------------------------------------------------------------------------------

#pragma once

//---[ WINDOW RELATED DEFINES ]-------------------------------------------------
#define WINDOW_WIDTH   800
#define WINDOW_HEIGHT  600
#define WINDOW_CAPTION "Project Name"

//---[ GAME RELATED DEFINES ]---------------------------------------------------
#define FRAMES_PER_SECOND 60
#define FRAME_RATE 1000/FRAMES_PER_SECOND
#define PLAYERMOVE 1.0f
#define GAMELEFT 17
#define GAMETOP 13
#define GAMERIGHT 545
#define GAMEBOTTOM 586

sprite.h
//------------------------------------------------------------------------------
// Project: Project Name
// File: sprite.h
//------------------------------------------------------------------------------

#ifndef SPRITE_H 
#define SPRITE_H 

class CSprite
{
	public:
		int init(char *dir, SDL_Surface *screen);
		void draw();
		void clearBG();
		void updateBG();
		
		float getX();
		float getY();
		float getW();
		float getH();
		
		void setX (float x);
		void setY (float y);
		void setW (int w);
		void setH (int h);
		void setPos (float x, float y);
		void setDim (int w, int h);
		
		void addX (float x);
		void addY (float y);
		
	private:
		SDL_Surface *m_Image;
		SDL_Surface *m_BackReplacement;
		SDL_Surface *m_Screen;
		float m_X;
		float m_Y;
		float m_OldX;
		float m_OldY;
		int m_H;
		int m_W;
};

#endif


sprite.cpp
//------------------------------------------------------------------------------
// Project: Project Name
// File: sprite.cpp
//------------------------------------------------------------------------------

//---[ LINKED LIBRARIES ]-------------------------------------------------------
#pragma comment(lib, "SDL.lib")
#pragma comment(lib, "SDLmain.lib")

//---[ INCLUDES ]---------------------------------------------------------------
#if defined(_MSC_VER)
#include "SDL.h"
#else
#include "SDL/SDL.h"
#endif

#include "defines.h"
#include "sprite.h"

//---[ NAMESPACE DECLARATION ]--------------------------------------------------

//---[ STRUCTURES ]-------------------------------------------------------------

//---[ GLOBAL VARIABLES ]-------------------------------------------------------

//---[ FUNCTION FORWARD DECLARATIONS ]------------------------------------------

//---[ FUNCTIONS ]--------------------------------------------------------------
int CSprite::init(char *dir, SDL_Surface *screen)
{
	SDL_Surface *temp;
			
	if((temp = SDL_LoadBMP(dir)) == NULL) return -1;

	SDL_SetColorKey(temp, SDL_SRCCOLORKEY, SDL_MapRGB(temp->format, 0, 255, 0));
                    
	m_Image = SDL_DisplayFormat(temp);

	SDL_FreeSurface(temp);
	
	m_Screen = screen;

	m_W = m_Image->w;	
	m_H = m_Image->h;
	
	return 0;
}

void CSprite::draw()
{
	SDL_Rect dest;
	dest.x = (int)m_X; dest.y = (int)m_Y;
	SDL_BlitSurface(m_Image, NULL, m_Screen, &dest);
}

void CSprite::clearBG()
{
	SDL_Rect dest;
	dest.x = (int)m_OldX;
	dest.y = (int)m_OldY;
	dest.w = m_W;
	dest.h = m_H;
	SDL_BlitSurface(m_BackReplacement, NULL, m_Screen, &dest);
}

void CSprite::updateBG()
{
	SDL_Rect srcrect;
	srcrect.w = m_W;
	srcrect.h = m_H;
	srcrect.x = (int)m_X;
	srcrect.y = (int)m_Y;
	m_OldX = m_X;
	m_OldY = m_Y;
	SDL_BlitSurface(m_Screen, &srcrect, m_BackReplacement, NULL);
}
		
float CSprite::getX()
{
	return m_X;
}

float CSprite::getY()
{
	return m_Y;
}

float CSprite::getW()
{
	return m_W;
}

float CSprite::getH()
{
	return m_H;
}
		
void CSprite::setX (float x)
{
	m_X = x;
}

void CSprite::setY (float y)
{
	m_Y = y;
}

void CSprite::setW (int w)
{
	m_W = w;
}

void CSprite::setH (int h)
{
	m_H = h;
}

void CSprite::setPos (float x, float y)
{
	m_X = x;
	m_Y = y;
}

void CSprite::setDim (int w, int h)
{
	m_W = w;
	m_H = h;
}
		
void CSprite::addX (float x)
{
	m_X += x;
}

void CSprite::addY (float y)
{
	m_Y += y;
}


main.cpp
//------------------------------------------------------------------------------
// Project: Project Name
// File: main.cpp
//------------------------------------------------------------------------------

//---[ LINKED LIBRARIES ]-------------------------------------------------------
#pragma comment(lib, "SDL.lib")
#pragma comment(lib, "SDLmain.lib")
//#pragma comment(lib, "SDL_TTF.lib")

//---[ INCLUDES ]---------------------------------------------------------------
#if defined(_MSC_VER)
#include "SDL.h"
//#include "SDL_TTF.h"
#else
#include "SDL/SDL.h"
//#include "SDL/SDL_TTF.h"
#endif

#include <stack>
#include "defines.h"
#include "sprite.h"

//---[ NAMESPACE DECLARATION ]--------------------------------------------------
using namespace std;   

//---[ STRUCTURES ]-------------------------------------------------------------
struct StateStruct 
{
	void (*StatePointer)();
};

//---[ GLOBAL VARIABLES ]-------------------------------------------------------
stack<StateStruct> g_StateStack; //--[ State stack
SDL_Surface *g_Bitmap = NULL; //--[ Background image
SDL_Surface *g_Window = NULL; //--[ Backbuffer
SDL_Event g_Event; //--[ SDL event structure for input
int g_Timer; //--[ Timer

CSprite princess;

int g_KeyLeft;
int g_KeyRight;
int g_KeyUp;
int g_KeyDown;
int g_KeySpace;

//---[ FUNCTION FORWARD DECLARATIONS ]------------------------------------------
void Menu();
void Game();
void Exit();

void DrawBackground();
void ClearScreen();
//void DisplayText(string text, int x, int y, int size, int fR, int fG, int fB, int bR, int bG, int bB);

void HandleMenuInput();
void HandleGameInput();
void HandleExitInput();

void UpdateGame();

void Init();
void Shutdown();

//---[ MAIN FUNCTION ]----------------------------------------------------------
int main(int argc, char **argv)
{
	Init();
	
	while (!g_StateStack.empty()) //--[ Break if Game State is empty
	{
		g_StateStack.top().StatePointer();		
	}

	Shutdown();

	return 0;
}


//---[ INITIALISATION FUNCTION ]------------------------------------------------
void Init()
{
	if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0)
	{
		printf("Unable to init SDL: %s\n", SDL_GetError());
		exit(1);
	}
	
	atexit(SDL_Quit);
	
	g_Window = SDL_SetVideoMode(WINDOW_WIDTH, WINDOW_HEIGHT, 0, SDL_ANYFORMAT);    

	if(g_Window == NULL)
	{
		printf("Unable to set 800 x 600 video: %s\n", SDL_GetError());
		exit(1);
	}

	SDL_WM_SetCaption(WINDOW_CAPTION, 0);

	g_Timer = SDL_GetTicks();

	g_Bitmap = SDL_LoadBMP("resources/graphics/background/menu background.bmp");	   

	princess.init("resources/graphics/sprites/princess/standstill/princess.bmp",g_Window);
	
	princess.setPos(200, 200);

	StateStruct state;
	state.StatePointer = Exit;
	g_StateStack.push(state);

	state.StatePointer = Menu;
	g_StateStack.push(state);	

	//TTF_Init();  //--[ Uncomment once have SDL_ttf Library
}

//---[ SHUTDOWN FUNCTION ]------------------------------------------------------
void Shutdown()
{
	//TTF_Quit(); //--[ Uncomment once have SDL_ttf Library

	SDL_FreeSurface(g_Bitmap);
	SDL_FreeSurface(g_Window);

	SDL_Quit();
}

//---[ MAIN MENU FUNCTION ]-----------------------------------------------------
void Menu()
{
	if ( (SDL_GetTicks() - g_Timer) >= FRAME_RATE ) //--[ Keep rate at 30fps
	{
		HandleMenuInput(); //--[ Process all input

		ClearScreen(); //--[ Clear everything from previous frame
		
		g_Bitmap = SDL_LoadBMP("resources/graphics/background/menu background.bmp");
		DrawBackground();

		//DisplayText("Start (G)ame", 350, 250, 12, 255, 255, 255, 0, 0, 0);
		//DisplayText("(Q)uit Game",  350, 270, 12, 255, 255, 255, 0, 0, 0);
			
		SDL_UpdateRect(g_Window, 0, 0, 0, 0); //--[ Display backbuffer

		g_Timer = SDL_GetTicks();
	}	
}

//---[ GAME FUNCTION ]----------------------------------------------------------
void Game()
{	
	if ( (SDL_GetTicks() - g_Timer) >= FRAME_RATE ) //--[ Keep rate at 30fps
	{
		HandleGameInput(); //--[ Process all input

		ClearScreen(); //--[ Clear everything from previous frame

		g_Bitmap = SDL_LoadBMP("resources/graphics/background/game background.bmp");
		DrawBackground();

		UpdateGame();
		
		SDL_UpdateRect(g_Window, 0, 0, 0, 0); //--[ Display backbuffer
		
		g_Timer = SDL_GetTicks();
	}	
}

//---[ EXIT SCREEN FUNCTION ]---------------------------------------------------
void Exit()
{	
	if ( (SDL_GetTicks() - g_Timer) >= FRAME_RATE ) //--[ Keep rate at 30fps
	{
		HandleExitInput(); //--[ Process all input

		ClearScreen(); //--[ Clear everything from previous frame
		
		g_Bitmap = SDL_LoadBMP("resources/graphics/background/exit background.bmp");
		DrawBackground();

		//DisplayText("Quit Game (Y or N)?", 350, 250, 12, 255, 255, 255, 0, 0, 0);

		SDL_UpdateRect(g_Window, 0, 0, 0, 0); //--[ Display backbuffer

		g_Timer = SDL_GetTicks();
	}	
}

//---[ DRAW BACKGROUND FUNCTION ]-----------------------------------------------
void DrawBackground() 
{
	SDL_Rect source = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT };		
	SDL_Rect destination = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT };
	
	SDL_BlitSurface(g_Bitmap, &source, g_Window, &destination);
}

//---[ CLEAR SCREEN FUNCTION ]--------------------------------------------------
void ClearScreen()
{
	SDL_FillRect(g_Window, 0, 0);
}

//---[ DISPLAY TEXT FUNCTION ]--------------------------------------------------
//void DisplayText(string text, int x, int y, int size, int fR, int fG, int fB, int bR, int bG, int bB) 
//{
	//Open our font and set its size to the given parameter. //
    //TTF_Font* font = TTF_OpenFont("arial.ttf", size);

	//SDL_Color foreground  = { fR, fG, fB};   // Text color. //
	//SDL_Color background  = { bR, bG, bB };  // Color of what's behind the text. //

	// This renders our text to a temporary surface. There //
	// are other text functions, but this one looks nice.  //
	//SDL_Surface* temp = TTF_RenderText_Shaded(font, text.c_str(), foreground, background);

	// A structure storing the destination of our text. //
	//SDL_Rect destination = { x, y, 0, 0 };
	
	// Blit the text surface to our window surface. //
	//SDL_BlitSurface(temp, NULL, g_Window, &destination);

	// Always free memory! //
	//SDL_FreeSurface(temp);

	// Close the font. //
	//TTF_CloseFont(font);
//}

//---[ UPDATE GAME FUNCTION ]---------------------------------------------------
void UpdateGame()
{
	princess.clearBG();
	princess.updateBG();

	if (g_KeyLeft)
	{
		if (princess.getX() - PLAYERMOVE > GAMELEFT)
		{
			princess.addX(-PLAYERMOVE);
		}
	}
	
	if (g_KeyRight)
	{
		if (princess.getX() + PLAYERMOVE < GAMERIGHT - princess.getW())
		{
			princess.addX(PLAYERMOVE);
		}
	}
	
	if (g_KeyUp)
	{
		if (princess.getY() - PLAYERMOVE > GAMETOP)
		{
			princess.addY(-PLAYERMOVE);
		}
	}
	
	if (g_KeyDown)
	{
		if (princess.getY() + PLAYERMOVE < GAMEBOTTOM - princess.getH())
		{
			princess.addY(PLAYERMOVE);
		}
	}

	princess.draw();
	SDL_Flip(g_Bitmap);
}


//---[ MENU INPUT FUNCTION ]----------------------------------------------------
void HandleMenuInput() 
{
	if ( SDL_PollEvent(&g_Event) )
	{
		if (g_Event.type == SDL_QUIT)
		{			
			while (!g_StateStack.empty())
			{
				g_StateStack.pop();
			}
			return;
		}

		if (g_Event.type == SDL_KEYDOWN)
		{
			if (g_Event.key.keysym.sym == SDLK_ESCAPE)
			{
				g_StateStack.pop();
				return;
			}

			if (g_Event.key.keysym.sym == SDLK_q)
			{
				g_StateStack.pop();
				return;
			}

			if (g_Event.key.keysym.sym == SDLK_RETURN)
			{
				StateStruct temp;
				temp.StatePointer = Game;
				g_StateStack.push(temp);
				return;
			}
		}
	}
}

//---[ GAME INPUT FUNCTION ]----------------------------------------------------
void HandleGameInput() 
{
	while (SDL_PollEvent(&g_Event)) 
    {
    	switch (g_Event.type) 
    	{
    		case SDL_KEYDOWN:
   		
			switch (g_Event.key.keysym.sym)
    		{
    			case SDLK_LEFT:
          			g_KeyLeft = 1;
			        break;
        		case SDLK_RIGHT:
          			g_KeyRight = 1;
          			break;
        		case SDLK_UP:
          			g_KeyUp = 1;
          			break;
        		case SDLK_DOWN:
          			g_KeyDown = 1;
          			break;
        		case SDLK_SPACE:
          			g_KeySpace = 1;
          			break;
        	}
        	break;
        
      	case SDL_KEYUP:

        	switch (g_Event.key.keysym.sym)
			{
	        	case SDLK_ESCAPE:
					g_StateStack.pop();
					g_StateStack.pop();
					return;
	        	case SDLK_LEFT:
	        		g_KeyLeft = 0;
	          		break;
	        	case SDLK_RIGHT:
	          		g_KeyRight = 0;
	          		break;
	        	case SDLK_UP:
	          		g_KeyUp = 0;
	          		break;
	        	case SDLK_DOWN:
	          		g_KeyDown = 0;
	          		break;
	        	case SDLK_SPACE:
	          		g_KeySpace = 0;
	          		break;
            }
        	break;
      
	  	case SDL_QUIT:
    		while (!g_StateStack.empty())
				{
					g_StateStack.pop();
				}
				return;
		}
	}
}

//---[ EXIT INPUT FUNCTION ]----------------------------------------------------
void HandleExitInput() 
{
	if ( SDL_PollEvent(&g_Event) )
	{
		if (g_Event.type == SDL_QUIT)
		{			
			while (!g_StateStack.empty())
			{
				g_StateStack.pop();
			}
			return;
		}

		if (g_Event.type == SDL_KEYDOWN)
		{
			if (g_Event.key.keysym.sym == SDLK_ESCAPE)
			{
				g_StateStack.pop();
				return;
			}

			if (g_Event.key.keysym.sym == SDLK_y)
			{
				g_StateStack.pop();
				return;
			}

			if (g_Event.key.keysym.sym == SDLK_n)
			{
				StateStruct temp;
				temp.StatePointer = Menu;
				g_StateStack.push(temp);
				return;
			}
		}
	}
}

All help appreciated... ~ Jordan

Share this post


Link to post
Share on other sites
Advertisement
For one, you will need to add this function in:

~CSprite()
{
SDL_FreeSurface(m_Image);
}


But the main root of all evil in your code is that you are calling
g_Bitmap = SDL_LoadBMP("Some File.bmp"); without freeing the memory it causes major leeks.

So what you need to do is inside every statement that you have one of those g_Bitmap = lines, you will need to add to the end "SDL_FreeSurface(g_Bitmap);". That way at least you are freeing the memory that you load rather than letting it accumulate. So fix those in the Exit, Game, and menu functions, and that should take care of a lot of them.

However, the painstaking issue of effeciency is still there so rather than fix that, make these changes [smile].



... Globals ...
SDL_Surface* MenuBMP;
SDL_Surface* GameBMP;
SDL_Surface* ExitBMP;

... In the Init Function ...
MenuBMP = SDL_LoadBMP("resources/graphics/background/menu background.bmp");
GameBMP = SDL_LoadBMP("resources/graphics/background/game background.bmp");
ExitBMP = SDL_LoadBMP("resources/graphics/background/exit background.bmp");
...

//---[ MAIN MENU FUNCTION ]-----------------------------------------------------
void Menu()
{
if ( (SDL_GetTicks() - g_Timer) >= FRAME_RATE ) //--[ Keep rate at 30fps
{
HandleMenuInput(); //--[ Process all input

ClearScreen(); //--[ Clear everything from previous frame
/*****/
g_Bitmap = MenuBMP;
/*****/

DrawBackground();

//DisplayText("Start (G)ame", 350, 250, 12, 255, 255, 255, 0, 0, 0);
//DisplayText("(Q)uit Game", 350, 270, 12, 255, 255, 255, 0, 0, 0);

SDL_UpdateRect(g_Window, 0, 0, 0, 0); //--[ Display backbuffer

g_Timer = SDL_GetTicks();
}
}

//---[ GAME FUNCTION ]----------------------------------------------------------
void Game()
{
if ( (SDL_GetTicks() - g_Timer) >= FRAME_RATE ) //--[ Keep rate at 30fps
{
HandleGameInput(); //--[ Process all input

ClearScreen(); //--[ Clear everything from previous frame
/*****/
g_Bitmap = GameBMP;
/*****/
DrawBackground();

UpdateGame();

SDL_UpdateRect(g_Window, 0, 0, 0, 0); //--[ Display backbuffer

g_Timer = SDL_GetTicks();
}
}

//---[ EXIT SCREEN FUNCTION ]---------------------------------------------------
void Exit()
{
if ( (SDL_GetTicks() - g_Timer) >= FRAME_RATE ) //--[ Keep rate at 30fps
{
HandleExitInput(); //--[ Process all input

ClearScreen(); //--[ Clear everything from previous frame
/*****/
g_Bitmap = ExitBMP;
/*****/
DrawBackground();

//DisplayText("Quit Game (Y or N)?", 350, 250, 12, 255, 255, 255, 0, 0, 0);

SDL_UpdateRect(g_Window, 0, 0, 0, 0); //--[ Display backbuffer

g_Timer = SDL_GetTicks();
}
}

... Deinit Function ...
SDL_FreeSurface(MenuBMP);
SDL_FreeSurface(GameBMP);
SDL_FreeSurface(ExtBMP);





Now this way you just load once, then you can assign as necessary to get the right image to draw. For once thing though, you do not want to continously load BMP files then free, just to load them again. Ideally you will want to load once, then reuse until you no longer need them.

If you need any other help with this or explanations, feel free to ask! The first method should get rid of a lot of the memory leaks, but not all (due to the initial call to SDL_FreeSurface that is not called when the menu is entered after the menu is loaded from the init function) as well as a few other things. The second method should take away a lot of the problems as well. There's a few other things as well, but I'm sure you will ask if they cause problems later on.

As for the input lags, that might be from this last problem, and if not, it is because of your system of if ( (SDL_GetTicks() - g_Timer) >= FRAME_RATE ) //--[ Keep rate at 30fps

Share this post


Link to post
Share on other sites
Another thing you will eventually want to look into is SDL_DisplayFormat()

It converts any surface you load into the same format as the screen, resulting in faster blitting if the screen and surface had different formats.

here's an example of using it

SDL_Surface* temp = SDL_LoadBMP("test.bmp");
SDL_Surface* surfaceImGoingToUse = SDL_DisplayFormat(temp);

SDL_FreeSurface(temp);

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!