Ir ao conteúdo
  • Cadastre-se

Problemas com memória utilizada pelo programa.


Werex

Posts recomendados

Ola, estou fazendo um programa em c++ utilizando SDL. Porém, meu programa está usando valores absurdos de memória RAM. Ele é um programa simples mas inicia utilizando 40000 K de memória e vai subindo de 1000 em 1000 até valores absurdamente altos.

Eu ouvi dizer que isso poderia ser "Memory Leak". De acordo com o que pesquisei na internet parece ser isso mesmo. Porém, por mais que eu pesquise não faço ideia de como resolver isso.

Se alguem puder me explicar melhor como corrigir esse problema ou apenas me indicar uma fonte em português sobre o assunto, eu agradeceria.

Obrigado pela ajuda pessoal.

Link para o comentário
Compartilhar em outros sites

Desculpem por não ter postado o código antes, mas eu achei que ele estava grande de mais para postar aqui e fazer vocês ficarem procurando errinhos. Não tenho muita ideia de onde entá o erro, por isso postei tudo. Mas depois do código colocarei uma explicação mais detalhada do que está acontecendo.


#include <stdlib.h>
#include <SDL.h>
#include <windows.h>
#include <SDL_ttf.h>
#include <sstream>
#include <math.h>
#include "SDL_rotozoom.h"
using namespace std;




char* DoubleToChar(double x){
char c[100];
sprintf(c,"%f",x);
return c;
}

struct vetor{
double x;
double y;

};

int aproximar(int d){
int i;
if(d%1>0.5){
i=d+(1-(d%1));
}else{
i=d-(d%1);
}
return i;
}




//função dos vetores
vetor somarvetores(vetor vetor1,vetor vetor2){
vetor1.x=vetor1.x + vetor2.x;
vetor1.y=vetor1.y + vetor2.y;

return vetor1;
}

//MAIN
int main ( int argc, char** argv ){

SDL_Init(SDL_INIT_EVERYTHING);
TTF_Init();

restart:
double pii=3.15;
double testenum;
double passou;
double gravidadevalor;

int jh=900;
int jw=1440;
int FPS=70;
int cvm=1;
int cursory1,cursory2,cursorx1,cursorx2;
int Gravidade=50;
int vrr=0;
int vra;
int ang=359;
int raio=26;

bool pause = false;
bool holding=false;
bool running = true;
bool restart = false;



SDL_Surface *janela;
SDL_WM_SetCaption("Teste vetores", NULL);
janela = SDL_SetVideoMode(jw,jh,32,SDL_SWSURFACE);

SDL_Surface *icone;
icone = SDL_DisplayFormat(SDL_LoadBMP("bola.bmp"));
SDL_SetColorKey(icone,SDL_SRCCOLORKEY,SDL_MapRGB(janela->format, 0xff,0,0xff));
SDL_WM_SetIcon(icone,NULL);

SDL_Surface *bola[ang];
for(ang=0;ang<360;ang++){
bola[ang]=SDL_DisplayFormat(SDL_LoadBMP("imagens/bola_Nova.bmp"));
SDL_SetColorKey(bola[ang],SDL_SRCCOLORKEY,SDL_MapRGB(janela->format,0xff,0,0xff));
bola[ang] = rotozoomSurface(SDL_DisplayFormat(bola[ang]), ang,1,0);

}
SDL_Surface *brilho[ang];
for(ang=0;ang<360;ang++){
brilho[ang]=SDL_DisplayFormat(SDL_LoadBMP("imagens/brilho.bmp"));
SDL_SetColorKey(brilho[ang],SDL_SRCCOLORKEY,SDL_MapRGB(janela->format,0xff,0,0xff));
brilho[ang] = rotozoomSurface(SDL_DisplayFormat(brilho[ang]), ang,1,0);
SDL_SetAlpha(brilho[ang],SDL_SRCALPHA,150);

}
ang=0; //apenas ajeita o ângulo para que o rect não crashe o aplicativo

SDL_Surface *texto;
SDL_Color cortexto = {0,0,0};
TTF_Font *brewmastermodern = TTF_OpenFont("fontes/arial.ttf",50);




SDL_Rect pbola;
pbola.w=52;
pbola.h=52;
pbola.y=pbola.h;
pbola.x=jw/2;

SDL_Rect rbola;
rbola.w=bola[ang]->w;
rbola.h=bola[ang]->h;
rbola.y=rbola.h;
rbola.x=jw/2;

SDL_Rect sbola;
sbola.w=bola[ang]->w;
sbola.h=bola[ang]->h;





SDL_Rect teste;
teste.h=1;
teste.w=100;
teste.y=pbola.y;
teste.x=jw/2;



SDL_Rect rtexto;


SDL_Event evento;

//vetores

vetor cursor;

vetor gravidade;
gravidade.y=1;
gravidade.x=0;

vetor atritoar;
atritoar.x=0.2;


vetor velocidade;
velocidade.y=0;
velocidade.x=0;

//ang=390;
//inicio do Loop do jogo

while(running == true){
int inicio = SDL_GetTicks();



//eventos
while(SDL_PollEvent(&evento)){
switch(evento.type){
case SDL_QUIT:
running=false;
break;
case SDL_MOUSEMOTION:
cursor.x = evento.motion.x;
cursor.y = evento.motion.y;
//mouse down
case SDL_MOUSEBUTTONDOWN:
switch(evento.button.button){

case SDL_BUTTON_LEFT:
if(pbola.x<cursor.x && cursor.x<pbola.x+pbola.w && pbola.y<cursor.y && cursor.y<pbola.y+pbola.h)
holding=true;

break;


}
break;
//mouse up
case SDL_MOUSEBUTTONUP:
switch(evento.button.button){
case SDL_BUTTON_LEFT:
if(holding==true){
if(cvm==1){
velocidade.x=cursorx2-cursorx1;
velocidade.y=cursory2-cursory1;
}else{
velocidade.x=cursorx1-cursorx2;
velocidade.y=cursory1-cursory2;
}
}
holding=false;
}
break;

//teclado
case SDL_KEYDOWN:
switch (evento.key.keysym.sym){

case SDLK_ESCAPE:
running=false;
break;

case SDLK_BACKSPACE:
velocidade.x=0;
velocidade.y=0;
break;
case SDLK_r:
restart = true;
running=false;
break;
case SDLK_p:
pause=true;
}
}
break;
}

//ajuda a calcular velocidade do cursor
if(cvm==1){
cursorx1=cursor.x;
cursory1=cursor.y;
cvm=2;
}else{
cursorx2=cursor.x;
cursory2=cursor.y;
cvm=1;
}

//pause
while(pause==true){
while(SDL_PollEvent(&evento)){
switch(evento.type){
case SDL_KEYDOWN:
switch(evento.key.keysym.sym){
case SDLK_p:
pause=false;
break;
}
break;

}
}

}


//holding
if (holding==true){
pbola.y=cursor.y-(pbola.h/2);
pbola.x=cursor.x-(pbola.w/2);
velocidade.x=0;
velocidade.y=0;
}else{
pbola.x=pbola.x+velocidade.x;
pbola.y=pbola.y+velocidade.y;
}



//colisão paredes

if(pbola.y<=0){

pbola.y=0;
velocidade.y=velocidade.y*-1;
}

if(pbola.x+pbola.w>=jw){
pbola.x=jw-pbola.w;
velocidade.x=velocidade.x*-1;
}

if(pbola.x<=0){
pbola.x=0;
velocidade.x=velocidade.x*-1;
}

if(pbola.y+pbola.h>=jh){
pbola.y=jh-pbola.h;
velocidade.y=velocidade.y*-1;
vrr=360*(velocidade.x/(2*(pii*26)));


}else if(holding == true){


}else{
//soma dos vetores
velocidade = somarvetores(velocidade,gravidade);
}
vra=round(vrr);
ang=ang+(-vra);




//correção do ângulo

if(ang>359){
ang=0+(ang-360);
}else if(ang<0){
ang=360-(0-ang);
}


sbola.y=((bola[ang]->h)/2)-raio;
sbola.x=((bola[ang]->w)/2)-raio;


//atualizando textos
texto=TTF_RenderText_Solid(brewmastermodern,DoubleToChar(ang),cortexto);
rtexto.h=texto->h;
rtexto.w=texto->w;
rtexto.y=jh-rtexto.h;
rtexto.x=jw-rtexto.w;

//corrigindo movimento
rbola.y=pbola.y;
rbola.x=pbola.x;
if(pbola.y%1>=0.5){
rbola.y= rbola.y+(1-(pbola.y%1));
}else if(pbola.y%1<0.5){
rbola.y=rbola.y-(pbola.y%1);
}
if(pbola.x%1>0.5){
rbola.x= rbola.x+(1-(pbola.x%1));
}else if(pbola.y%1<0.5){
rbola.x=rbola.x-(pbola.x%1);
}
//sbola.x=pbola.x+(pbola.w/2)-(sbola.w/2);
//sbola.y=pbola.y+(pbola.h/2)-(sbola.h/2);
//printing
SDL_FillRect(janela,&janela->clip_rect,SDL_MapRGB(janela->format,0xdd,0xdd,0xdd));
SDL_FillRect(janela,&teste,SDL_MapRGB(janela->format,0,0,0xff));
SDL_BlitSurface(bola[ang],&sbola,janela,&pbola);
SDL_BlitSurface(brilho[0],NULL,janela,&pbola);
SDL_BlitSurface(texto,NULL,janela,&rtexto);


SDL_Flip(janela);
if((SDL_GetTicks()- inicio)<(1000/FPS)){
SDL_Delay((1000/FPS)-(SDL_GetTicks()-inicio));
}
}

//liberando memória
for(ang=0;ang<360;ang++){
SDL_FreeSurface(bola[ang]);
}
for(ang=0;ang<360;ang++){
SDL_FreeSurface(brilho[ang]);
}
SDL_FreeSurface(janela);
SDL_FreeSurface(texto);
TTF_CloseFont(brewmastermodern);

if(restart==true){
goto restart; //restart
}

TTF_Quit();
SDL_Quit();

return 0;
}

O programa também tem um acréscimo de memória quando aperto o botão "restart" que criei, a princípio pensei que esse acréscimo era causado pelo carregaento das imagens, mas mesmo depois que reorganizei o código para que o "restart" só ocorra depois dos "SDL_FreeSurface" o problema continua. Portanto, acredito que o pricipais suspeitos sejam as classes e structures que criei ou talvez até as variáveis.

Ah, antes que eu me esqueça. Sei que carregar 359 imagens de uma bolinha é um exagero, mas foi o única maneira que encontrei para fazer o programa funcionar com o rotozoom.h. Quando tentei fazer o programa calcular a rotação da bola em tempo real, o programa parou de funcionar, então a solução foi carregar tudo antes. Aproveitando o fato de que postei o código inteiro, gostaria de saber se tem uma maneira de otimizar isso também. Isso também vai ajudar a reduzir a memória utilizada pelo programa.

E lembrem-se, o código não está terminado, então se encontrarem algo inútil no meio é porque eu vou usar ainda. Ah, e me perdoem se eu cometi alguma "noobisse" no meio do código. Sou iniciante.

Obrigado pela atenção de todos.

Link para o comentário
Compartilhar em outros sites

Não sei se isso vai ajudar, mas aqui está um link para o download do programa:

http://www.4shared.com/rar/pEozZ0BC/testevetores.html

Quando você abrir o programa, veja a memória utilizada pelo programa no gerenciador de tarefas. Você vai notar que o uso de memória vai subindo cada vez mais.

Controles:

p- Pausa

r- Restart - Esse comando adiciona uns 20000 k de utilização de memória pelo programa, ele é uma das fontes do problema.

Backspace- Zera a velocidade da bola.

Vou dar mais uma pesquisada aqui para ver se eu acho uma solução. Se eu conseguir, eu posto aqui.

Ah, e obrigado pela atenção Waltton ;)

Link para o comentário
Compartilhar em outros sites

Olhando "por cima" parece que você esta criando uma nova "Surface" com o texto a cada interação do loop.


texto=TTF_RenderText_Solid(brewmastermodern,DoubleToChar(ang),cortexto);

e você só esta liberando ela da memoria no final do programa ao invés do final do loop.

A função SDL_LoadBMP retorna uma "surface" e a SDL_DisplayFormat cria uma copia em outro formato, portanto você tem que liberar a "surface" criada pela SDL_LoadBMP após a "conversão".


for(ang=0;ang<360;ang++){
bola[ang]=SDL_DisplayFormat(SDL_LoadBMP("imagens/bola_Nova.bmp"));
SDL_SetColorKey(bola[ang],SDL_SRCCOLORKEY,SDL_MapRGB(janela->format,0xff,0,0xff));
bola[ang] = rotozoomSurface(SDL_DisplayFormat(bola[ang]), ang,1,0);

}
SDL_Surface *brilho[ang];
for(ang=0;ang<360;ang++){
brilho[ang]=SDL_DisplayFormat(SDL_LoadBMP("imagens/brilho.bmp"));
SDL_SetColorKey(brilho[ang],SDL_SRCCOLORKEY,SDL_MapRGB(janela->format,0xff,0,0xff));
brilho[ang] = rotozoomSurface(SDL_DisplayFormat(brilho[ang]), ang,1,0);
SDL_SetAlpha(brilho[ang],SDL_SRCALPHA,150);

}

Corrija esses problemas, depois procuraremos mais.

Link para o comentário
Compartilhar em outros sites

Muito obrigado hacker_wap! Só foi liberar a superfície do texto no final do loop que o uso de memória já se estabilizou. Você entende mesmo do assunto heim.^_^

Então espera aí, deixe-me ver se entendi: Sempre que eu igualo uma surface à alguma coisa:


SDL_Surface *texto;
texto=SDL_LoadBMP(imagem1);

eu não estou substituindo o que eu havia antes nessa surface e sim adicionando algo novo, por isso o uso de memória aumenta? Isso significa que sempre que eu quiser modificar a imagem contida na surface eu preciso liberar o que tem nela antes?

exemplo:


SDL_Surface *texto;
texto=SDL_LoadBMP(imagem1);
SDL_FreeSurface(texto);
texto=SDL_LoadBMP(imagem2);

Ah, e estou trabalhando para corrigir os outros erros. Agora que já conheço os principais suspeitos ficará mais fácil de resolver. Quando eu conseguir eu postarei as modificações realizada. Obrigrado pela atenção de todos ;)

Link para o comentário
Compartilhar em outros sites

Então espera aí, deixe-me ver se entendi: Sempre que eu igualo uma surface à alguma coisa:


SDL_Surface *texto;
texto=SDL_LoadBMP(imagem1);

Basicamente é isso sim, a variavel texto é um ponteiro para uma surface(armazena o endereço de uma), SDL_LoadBMP cria uma surface baseada no arquivo e retorna um ponteiro para ela, quando você faz a atribuição você troca o endereço que texto aponta, o conteúdo que ele apontava antes continua existindo.

Então sim, sempre que você quiser trocar o conteúdo que a variável aponta, o anterior deve ser liberado.

Nesse trecho aqui.


brilho[ang]=SDL_DisplayFormat(SDL_LoadBMP("imagens/brilho.bmp"));

o retorno da SDL_LoadBMP esta ficando perdido pois não esta sendo armazenado em lugar nenhum.

Link para o comentário
Compartilhar em outros sites

SDL_Surface  *bolac[ang];
SDL_Surface *bola[ang];
for(ang=0;ang<360;ang++){
bolac[ang]=SDL_LoadBMP("imagens/bola_Nova.bmp");
SDL_SetColorKey(bolac[ang],SDL_SRCCOLORKEY,SDL_MapRGB(janela->format,0xff,0,0xff));
bolac[ang] = rotozoomSurface(bolac[ang], ang,1,0);
bola[ang] = SDL_DisplayFormat(bolac[ang]);
SDL_SetColorKey(bola[ang],SDL_SRCCOLORKEY,SDL_MapRGB(janela->format,0xff,0,0xff));
SDL_FreeSurface(bolac[ang]);

}

Assim está correto? O problema desse método que usei é que o código parece ficar muito poluído já que tenho que criar duas surfaces para que tudo funcione. Isso é normal? Foi a única maneira que consegui fazer funcionar junto com o color key. E realmente reduziu em muito o uso de memóra. Antes começava com 40000k agora somente com 27000k. Antes toda vez que eu apertava o botão "restart" o programa ganhava 20000k de memória e agora com meus vários testes de tentativa e erro consegui um mínimo de 10000k por restart. Muito obrigado hacker_wap.

Fiz algumas pesquisas e descobri algumas coisas interessantes sobre os comandos que estou usando.

Esta página até tem um aviso sobre o memory leak que o SDL_DisplayFormat pode gerar:

http://sdl.beuc.net/sdl.wiki/SDL_DisplayFormat

As vezes parece que o código fica melhor sem o SDL_DisplayFormat.

Ah, e desculpem por estar prolongando demais esse tópico, mas já pesquisei em inglês, português e até em espanhol e não consegui achar aguma coisa que me ajude efetivamente a resolver esse problema. Até pensei em modificar o funcionamento botão de restart, mas isso implicaria em uma mudaça brusca na estrutura do código ou poderia me trazer problemas mais tarde. Além disso, é melhor aprender a consertar isso agora do que jogar o problema para baixo do tapete e futuramente precisar criar outro tópico para resolver isso. Mais uma vez agradeço a atenção de todos.

Link para o comentário
Compartilhar em outros sites

pelo que eu andei lendo rotozoomSurface também retorna uma nova surface, então você tem que liberar ela também.

eu faria esse trecho da seguinte forma.


SDL_Surface *bolas[ang];
SDL_Surface *bola = SDL_LoadBMP("imagens/bola_Nova.bmp");

SDL_SetColorKey(bola, SDL_SRCCOLORKEY, SDL_MapRGB(janela->format, 0xff,0, 0xff));

for(ang = 0; ang < 360; ++ang) {
SDL_Surface *temp = rotozoomSurface(bola, ang, 1, 0);
bolas[ang] = SDL_DisplayFormat(temp);
SDL_FreeSurface(temp);
}

SDL_FreeSurface(bola);

Apesar da mudança do código o comportamento deve se manter o mesmo.

Também faria o mesmo para a parte do brilho, talvez até juntasse as duas em um único loop.

Quanto ao restart eu colocaria ele bem mais abaixo aonde as variáveis de controle são inicializadas para não ter que fazer o carregando das imagens novamente, atualmente pelo que vi quando ocorre o restart você faz tudo de novo mais não libera as surfaces que existiam.

Agora sinceramente eu preferiria refazer todo esse código de forma diferente evitando goto, criando funções para realizar tarefas comuns, tentando simplificar o código etc..

Sobre a SDL_DisplayFormat ela retorna uma surface no formato padrão do vídeo assim fica mais rápido para ele trabalhar com ela, você não precisa realizar a conversão se o desempenho no formato normal esta bom para você, porém lembre-se que ainda que agora o desempenho seja satisfatório futuramente quando você adicionar mais coisas ele pode deixar de ser e você vai ter que alterar o código(eu preferiria já fazer tudo agora).

de qualquer forma estamos aqui para qualquer duvida :)

Link para o comentário
Compartilhar em outros sites

Muito obrigado hacker_wap! O código final ficou assim:

SDL_Surface *bola[ang];
SDL_Surface *bolac = SDL_LoadBMP("imagens/bola_Nova.bmp");
SDL_SetColorKey(bolac,SDL_SRCCOLORKEY,SDL_MapRGB(janela->format,0xff,0,0xff));
for(ang=0;ang<360;ang++){
SDL_Surface *temp = rotozoomSurface(bolac,ang,1,0);
SDL_SetColorKey(temp,SDL_SRCCOLORKEY,SDL_MapRGB(janela->format,0xff,0,0xff));

//foi necessário usar um segundo SDL_SetColorKey. Se eu retirar qualquer um dos dois SDL_SetColorKey a imagem não carregará adequadamente.

bola[ang]=SDL_DisplayFormat(temp);
SDL_FreeSurface(temp);
}
SDL_FreeSurface(bolac);

Agora está tudo completamente estável! :D

Até quando aperto o botão de restart!

Eu tive alguns problemas; por algum motivo, quando usei esta mesma técnica com o brilho, o programa começou a crashar depois do primeiro restart. Descobri que a causa era o SDL_FreeSurface(). Porém, decidi esquecer esse nogócio de colocar uma iluminação dinâmica nesse programa e resolvi carregar somente uma imagem de brilho. Isso deixou o programa incrivelmente mais leve. Agora ele apenas usa 13000k de memória.:)

E realmente, fazer um botão de restart com o comando "goto" foi uma tremenda furada, da próxima vez vou bolar uma maneira mais fácil de criar esse botão. Mas apesar de tudo, tive a oportunidade de aprender mais sobre as surfaces e os comandos básicos do SDL. E agora sei como resolver esses problemas de memory leak quando eu precisar.

Posteriormente colocarei um modo de interação com botões e em breve postarei aqui o programa completo para quem quiser dar uma olhada no código. E com certeza colocarei você hacker_wap nos "agradecimentos especiais". Muito obrigado!

Link para o comentário
Compartilhar em outros sites

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...