Massive memory leak

Started by
13 comments, last by alvaro 10 years, 11 months ago

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.

Advertisement

My first tool against memory leaks is discipline:

(1) Use standard containers (of objects, not pointers) instead of rolling your own data structures.

(2) Use a smart pointer (probably std::unique_ptr) when you need polymorphism.

(3) Be very clear about which object owns which resource, and release the resource in the object's destructor.

Now that you already have a mess because you probably haven't followed the principles above, you can try to use tools like valgrind to help you find problems with how you are using memory. It is a pretty safe bet that `new' is involved.

Massive memory leaks should be easier to detect than small ones. There is also more of an incentive to fix them. :)

I am not very familiar with SFML, so I won't comment on the second part of your post.

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.

openwar - the real-time tactical war-game platform

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

VladR My 3rd person action RPG on GreenLight: http://steamcommunity.com/sharedfiles/filedetails/?id=92951596

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/

Currently working on a scene editor for ORX (http://orx-project.org), using kivy (http://kivy.org).

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.

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).

I'm working on a game! It's called "Spellbook Tactics". I'd love it if you checked it out, offered some feedback, etc. I am very excited about my progress thus far and confident about future progress as well!

http://infinityelephant.wordpress.com

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.

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?

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.

This topic is closed to new replies.

Advertisement