• Advertisement
Sign in to follow this  

Massive memory leak

This topic is 1709 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

I am working on a project for a long time now and wasn't paying much attention to memory issues since they didn't cause any problems so far but I believe they will at some point. There are some actions to be taken like providing smaller assets to players that don't use/have full HD compatible displays and optimize some assets, yet I would like to know how do you guys (or girls why not!) deal with memory leaks. Is there something particularly important that I should look for when tracking the leaks? Are the leaks necessarily linked to "new" usage or should I look somewhere else too? Should a massive memory leak always be obvious to detect?

 

Also there is a second point, more specific for SFML users: I am using a resource manager class that loads all assets and provide them the other classes as needed or at the game boot. The resource manager holds sf::Image's and the classes that need to drawn something holds sf::Sprite's. Now, if I have two,three,four...a thousand similar instances of this class, will the resource manager still take just the memory needed for one sf::Image used by the consumer class or each instance will take more and more memory? Does this make sense at all?

 

Thanks in advance.

Share this post


Link to post
Share on other sites
Advertisement

There's only one way to deal with leaks: Find them and fix them.

 

Leaks don't necessarily come from new/malloc statements in your own code, they could also happen indirectly if you don't call the proper cleanup methods in library code.

 

There are two methods to find leaks:

- Use a static analyzer that examines logical errors in your code.

- Run the executable using a memory profiler and watch for unreleased resources.

 

With good tools tiny leaks should be as easy to detect as massive ones.

Edited by Felix Ungman

Share this post


Link to post
Share on other sites

Should a massive memory leak always be obvious to detect?

Absolutely. I take it you check the memory footprint in Task manager. There's no way you could miss a massive leak this way.

 

Then again, your definition of massive leak may differ from mine...

 

 

Are the leaks necessarily linked to "new" usage or should I look somewhere else too?

In gamedev there are two major types of leaks - Memory Leaks and Resource leaks, which are caused by unreleased graphics resources (e.g. textures, RTs, VB / IB, ...). Those are best checked by DirectX debug runtime (change the setting in Control Panel and enjoy hundreds of colorful messages in Output pane of Visual Studio).

 

 

Also, if you are not using Smart Pointers and are still trying to match new/delete, there's nothing better than the experience of rolling out your own _NEW, _DELETE and going through the logs and matching it all.

 

Usually, that exercise alone is enough to persuade one it's really time to move to Smart Pointers smile.png

Share this post


Link to post
Share on other sites

Do you use linux (or may it)? If you do look for a program called valgrind.

 

It will give you a memory report that is very accurate and includes memory leaks and memory errors. I always validate my code with it.

 

The link for the project is here: http://valgrind.org/

Share this post


Link to post
Share on other sites

Also there is a second point, more specific for SFML users: I am using a resource manager class that loads all assets and provide them the other classes as needed or at the game boot. The resource manager holds sf::Image's and the classes that need to drawn something holds sf::Sprite's. Now, if I have two,three,four...a thousand similar instances of this class, will the resource manager still take just the memory needed for one sf::Image used by the consumer class or each instance will take more and more memory? Does this make sense at all?

Each sf::Image(or sf::Texture primarily in 2.0) is a unique instance. If you make 100 sf::Textures and tell them all to load the same file you'll have 100 copies of the image data. What you -should- do is keep one copy of the image in your resource manager and just return references to any caller asking for the object. You could do that by using an unordered_map or something using the key as the filepath of the object, or some kind of identifier like an assetname you invention up.

Each object can easily have it's own sf::Sprite, it's supposed to be a lightweight class from what I can tell. Then you can just set it to whatever image/texture you want to immediately use.

Share this post


Link to post
Share on other sites

Also there is a second point, more specific for SFML users: I am using a resource manager class that loads all assets and provide them the other classes as needed or at the game boot. The resource manager holds sf::Image's and the classes that need to drawn something holds sf::Sprite's. Now, if I have two,three,four...a thousand similar instances of this class, will the resource manager still take just the memory needed for one sf::Image used by the consumer class or each instance will take more and more memory? Does this make sense at all?

 

I'm not sure if this helps, but personally I have a small class based mostly around an std::map that holds my sf::texture objects (sf::image in your case).  That's the only place that textures get loaded and they are all loaded one time at startup.  The class has a getSpriteByKey method that returns an sf::sprite with a given texture/image attached to it.  I don't create sprites until I need them (though I do try to keep them around once I have created them if I know I'll need them again where possible).

Share this post


Link to post
Share on other sites

Thanks for the suggestions. They´ve helped me. I think I found the problem (or the worst part of it). I have a std::vector with dynamic allocated objects being pushed under a certain condition. The problem is that when another certain condition is met, I was just popping them. So I guess I should´ve used delete before popping them? Is this correct? I think this is the problem because after commenting this relevant part of the code my memory consumption has stopped to increase.

Share this post


Link to post
Share on other sites

Yep, that solved the problem. There are other minor leaks to fix so I´ll assume the same solution for now.

 

edit: just a note, I wasn´t popping the objects. I was doing "erase" from std::vector. I am still doing it but now I delete them before that. I read somewhere that I should nullify AND also delete. Is this correct?

Edited by CJ_COIMBRA

Share this post


Link to post
Share on other sites

Yep, that solved the problem. There are other minor leaks to fix so I´ll assume the same solution for now.

 

edit: just a note, I wasn´t popping the objects. I was doing "erase" from std::vector. I am still doing it but now I delete them before that. I read somewhere that I should nullify AND also delete. Is this correct?

Erase or pop_back do the same thing essentially, destroy the object. In the case of destroying pointers you literally just destroy that one pointer to the object and the object remains floating in memory, oblivious to the fact that no other pointers or references may have access to it. Obviously a memory leak.

 

Usually you set a pointer to NULL(which is 0) so that if you later check the pointer against null, you will know if it is currently pointing to a hopefully live object, or if it was set to point to nothing, perhaps to wait for you to assign it to something else.

 

On the flipside, delete frees the actual memory the pointer is pointing to, leaving the pointer still alive but pointing to a now dead object.

 

You probably know most of this, but I was just re-iterating as a start point. You only should set a pointer to null if it is going to be alive still. pop_back or delete, frees the actual pointer, so it won't exist any longer in the container, thus you don't really need to set it to null.

 

In other words: delete any allocated objects you are done using, set the pointer to null if it isn't going to be destroyed anyway. Though you might want to set it to null as a sanity check if you do something like.. declare it at the top of a function and someone might be tempted to use it at the bottom. That obviously isn't the case with regards to container classes since you won't be inside them. You definitely want to set things like member pointers to NULL.

Share this post


Link to post
Share on other sites

edit: just a note, I wasn´t popping the objects. I was doing "erase" from std::vector. I am still doing it but now I delete them before that. I read somewhere that I should nullify AND also delete. Is this correct?


You must call delete otherwise the object will still exist, but you don't need to set the pointer to NULL if you call erase or delete the entire vector as the pointer will be "destroyed" anyway. Actually setting it to NULL will be a wasted instruction.

Share this post


Link to post
Share on other sites

So you have a vector of pointers, in violation of my rule (1) above. Why not make it a vector or objects instead?

Share this post


Link to post
Share on other sites

Yeah, I tried that but for some reason it wont work in my case (everything seems fine but then it crashes every time the execution reaches the point that the object is pushed into the vector), so I changed back to pointers. Perhaps it's related to the class I am trying to push into the vector. I'll look more into that later, I just started to optimize and fix things on my project and I've seen that's it's going to be a huge work.

 

By the way do you know what would be the ideal amount of memory I should recommend based on how much my application uses? I mean, we see lots of games asking for 2GB minimum and 4 GB recommended (in example) but obviously those applications don't take 2GB or 4GB to run because there are other things happening on the system. Is there a "formula" that gives you the amount you should recommend based on how much you will in fact use?

 

Thanks again!

Share this post


Link to post
Share on other sites

Yeah, I tried that but for some reason it wont work in my case (everything seems fine but then it crashes every time the execution reaches the point that the object is pushed into the vector), so I changed back to pointers.

 

I would say go back to objects and fix the crash. You may have some other bug and the use of pointers is just masking it.

Share this post


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

  • Advertisement