Best practices for memory management

ensomari

Member
Hey guys,

I'm working on a game that has gradual slowdown where the fps drops significantly over the course of about an hour.

I've run the profiler and suspect it's more memory related than GPU/CPU related. I assume I probably have several memory leaks.

I'm familiar with memory management practices in C#, java, and even C++, but I'm not familiar with when exactly GML requires me to manage memory/destroy objects.

Can anyone give me some pointers on best practices for memory management for GML?
 

obscene

Member
I'd just make sure you are freeing / destroying every data structure, surface, etc. Anything that has a function to create it has a function to destroy it. instance_create/instance_destroy, surface_create/surface_free, ds_grid_create/ds_grid_destroy, part_type_create/part_type_destroy, audio_emitter_create/audio_emitter_destroy, etc. If I were double-checking I'd just do a search for "create" and make sure every script has a cleanup section at the bottom and every object has a Cleanup Event taking care of everything in that object.

If you wanted to automate the whole process you could write custom functions to create these types of things and save their IDs to a global array that can be read by a controller object at Room End and remove them all in bulk. I've done a lite version of that with audio emitters before and it worked well.

Obviously make sure you don't have any runaway instances (projectiles) or particle systems either.
 

TsukaYuriko

☄️
Forum Staff
Moderator
High memory usage, or memory leaks, for that matter, won't have any negative effect on your game's performance.

If you're experiencing performance issues, that's either caused by your CPU, GPU or by your entire PC running out of memory to the point where it has to put game-related stuff on the page file, which will be limited by your page file drive's speeds rather than RAM speeds. None of those are inherently caused by memory leaks, though.


Before we proceed, we have to make sure what kind of issues you're facing.

What are the profiler results? At how many FPS does your game start, to where do they drop, and roughly when does that happen?
 

Yal

🐧 *penguin noises*
GMC Elder
Hey guys,

I'm working on a game that has gradual slowdown where the fps drops significantly over the course of about an hour.

I've run the profiler and suspect it's more memory related than GPU/CPU related. I assume I probably have several memory leaks.

I'm familiar with memory management practices in C#, java, and even C++, but I'm not familiar with when exactly GML requires me to manage memory/destroy objects.

Can anyone give me some pointers on best practices for memory management for GML?
The object asset type (or, well, instances of them) has a bunch of automated processing attached to it, so if you spawn lots of object instances, you should delete them when you don't need them anymore. All their first-class variables (and arrays) are removed from memory when they're deleted, but all other dynamic data types (surfaces, data structures etc) are not.

You can monitor memory usage in the debug mode overlay - in GMS2 at least, you didn't mention which version you're using - so it could be worth checking that over time to see if you're actually leaking memory. (Try setting the game's speed to 9999 to speed up this process as much as possible)

If you're experiencing performance issues, that's either caused by your CPU, GPU or by your entire PC running out of memory to the point where it has to put game-related stuff on the page file, which will be limited by your page file drive's speeds rather than RAM speeds. None of those are inherently caused by memory leaks, though.
Memory fragmentation could slow things down even when memory isn't leaked, and leaking GPU memory increases texture page swaps. Though it's way easier to just write slow GML than to end up having to worry about either of those.
 

ensomari

Member
Thanks guys, great advice. I'm about to make counters for runaway instances, especially for projectiles. I'm using the the latest version of GMS 2.3.

I ran the profiler again, trying to make note of when FPS drops exactly. Turns out I was wrong assuming it's a memory leak.

My game is a top-down shooter with the main gameplay in a single room with many waves. Here's a table of memory usage and FPS throughout a standard play session. I recorded values when waiting for the next wave to start, so it's not like there's thousands of projectiles on the screen at later data points.

1603471720593.png

(If I go beyond wave 70, the FPS drops below 30 and the game is essentially unplayable)

1603471201205.png
I'm not sure if there's a profile data log file I can attach, but here is some more info with time spent executing parts of my code. Running projectiles takes the longest, but again, there are essentially no projectiles on the screen when I made note of the FPS above.

So I guess... what could be causing the FPS to gradually decrease like this while memory usage appears to remain the same?
 

obscene

Member
Memory is climbing slightly... are there particle systems and components you aren't freeing? I'm guessing your projectiles are making particles based on the step usage? When you go back to your main menu is the memory restored to 1209? Seems like something is going very wrong by wave 50.
 

ensomari

Member
Yeah there's something going on but it's not particles... I haven't learned how to use them yet.

instance_count is revealing there's definitely some runaway instances.

I built this code to write all the instances that exist every minute

Now I think I've discovered the culprit...

GML:
// Place to check for runaway instances
if (global.debugMode && global.frame mod (60 * 60) == 0)
{
    show_debug_message("Printing all instances...");
    for (var i=0; i<instance_count; i++)
    {
        var inst = instance_id_get(i);
        with (inst)
        {
            show_debug_message(object_get_name(object_index));
        }
    }
    show_debug_message("--------------");
    show_debug_message("--------------");
    show_debug_message("--------------");
    show_debug_message("...Done");
}
 

TsukaYuriko

☄️
Forum Staff
Moderator
Note that the debugger itself also provides a list of all active instances to you - you don't have to make your own script for this. ;)

Play the game up to the point where the FPS drop is substantial, then check this list. There may be several hundred of the same instance in the list, pointing towards their object not properly destroying itself when no longer needed.
 

TheouAegis

Member
How are you destroying projectiles? And are you actually destroying them or are you deactivating them?

Personally I like recycling my instances, but that of course would set a hard limit on how many projectiles would be allowed (if you run out of available instances, no 'new' projectiles).
 
E

enriqe

Guest
Hi.
Did you find solution finally?
At what moment exactly you destroy instance of your projectile?
 

bandman28

Member
I suggest you use a type of memory holding called JSON, or JavaScript Object Notation, which never leaks memory.
It consists for small or large memory packages, using ds_list() and ds_map().
I recommend you watch this video for more information.
I have a feeling I understood this conversation wrong, but I hope not.
Hope this helped! ;)
 

Yal

🐧 *penguin noises*
GMC Elder
I've run the profiler and suspect it's more memory related than GPU/CPU related. I assume I probably have several memory leaks.
It's dangerous to assume things without evidence! You could end up making your code run worse if you optimize the wrong thing.
You can monitor memory usage as well in debug mode, it's in one of the data plots. If you can, try increasing the game speed to a large number (e.g. 99,999 frames per second) to speed up all the processing, this should make slow effects like memory leaks more easy to follow.
 
Top