Common sources of excessive RAM usage?

MysticalMist

Well-known member
So I'm in the midst of optimizing and debugging my project and I realized (albeit I should've caught onto this sooner rather than later) that my game has used a concerning amount of RAM (aka almost 1.5G) and there's not even that many entities or data that would would warrant that kind of stress on the engine. I'm correcting code and I will say I have at least taken care of some overlapping/excessive scripts but I can't help but feel like I'm missing some more painfully obvious things. What would anyone else suggest?

I was able to reduce the usage to at least roughly 807,800 to 819,800 kb on average, but that's still dangerously concerning from what I can tell.
 
So I'm in the midst of optimizing and debugging my project and I realized (albeit I should've caught onto this sooner rather than later) that my game has used a concerning amount of RAM (aka almost 1.5G) and there's not even that many entities or data that would would warrant that kind of stress on the engine. I'm correcting code and I will say I have at least taken care of some overlapping/excessive scripts but I can't help but feel like I'm missing some more painfully obvious things. What would anyone else suggest?

I was able to reduce the usage to at least roughly 807,800 to 819,800 kb on average, but that's still dangerously concerning from what I can tell.

That is indeed an absurd amount of RAM usage, and makes no sense at all. just for reference, the entire sprite set of Street Fighter 3, ~1000 unique images each, fits on less than 20MB. I have tons and tons of heavy script controlling logic, generating screens and so on, and they fit on less than 100MB.

Something is way, WAY off. Are you sure you're measuring correctly? If so, give us an overview of the design. Sprites, sounds, scripts, levels, and so on. It's almost impossible to have that kind of memory use unless you have a really bad leak somewhere. Hopefully we can find it.

DC
 
That is indeed an absurd amount of RAM usage, and makes no sense at all. just for reference, the entire sprite set of Street Fighter 3, ~1000 unique images each, fits on less than 20MB. I have tons and tons of heavy script controlling logic, generating screens and so on, and they fit on less than 100MB.

Something is way, WAY off. Are you sure you're measuring correctly? If so, give us an overview of the design. Sprites, sounds, scripts, levels, and so on. It's almost impossible to have that kind of memory use unless you have a really bad leak somewhere. Hopefully we can find it.

DC
It's really nothing different compared to another beat' em up. There's only 112 cached entities and 38 loaded ones upon starting the game. Sprites are indexed pngs, and most of the audio are .ogg files, though I'm not sure how much that affects the performance. I'm still checking for anything unnecessary or overlaps in the scripts.
 
It's really nothing different compared to another beat' em up. There's only 112 cached entities and 38 loaded ones upon starting the game. Sprites are indexed pngs, and most of the audio are .ogg files, though I'm not sure how much that affects the performance. I'm still checking for anything unnecessary or overlaps in the scripts.
Looking back on my previous versions/incremental saves of this project prior, apparently this issue had persisted for a long time. I'm honestly worried since this is roughly at least a year's work and I dunno where this leak came from. I really don't want to ruin my project and let this hold it back so I am admittedly way too eager to take care of this problem.
 
Looking back on my previous versions/incremental saves of this project prior, apparently this issue had persisted for a long time. I'm honestly worried since this is roughly at least a year's work and I dunno where this leak came from. I really don't want to ruin my project and let this hold it back so I am admittedly way too eager to take care of this problem.

Don't get too worried, it is probably something simple, and whatever it is I am sure we can solve it. If I have an issue I can't resolve through conventional debugging, I do one of two things, which kind of depends on my needs.

The first, is to make a full copy, then start taking out parts and testing. If the problem goes away, you probably found the issue. The other takes longer but is more certain and precise. You Start fresh, and copy bits over little by little and test. When the problem appears, you know for sure what caused it.

@Kratus is also good at debugging and might have some suggestions.

DC
 
Don't get too worried, it is probably something simple, and whatever it is I am sure we can solve it. If I have an issue I can't resolve through conventional debugging, I do one of two things, which kind of depend son my needs.

The first, is to make a full copy, then start taking out parts and testing. If the problem goes away, you probably found the issue. The other takes longer but is more certain and precise. You Start fresh, and copy bits over little by little and test. When the problem appears, you know for sure what caused it.

@Kratus is also good at debugging and might have some suggestions.

DC

Just did the latter with the neo geo edit pak as my base. I think I made a breakthrough?

When I made a scripts folder (with literally nothing in it) and added my scripts.txt file into it. The memory usage suddenly jumped up to 624.336 kb.

Here's my scripts.txt file for reference. Chances are I knew I overdid it but idk which one to reduce or how I could improve this.

Code:
#maxscriptvars {int}
#define a variable list in each script that can be accessed by index
#use getscriptvar(index) and setscriptvar(index, value) to use those variables
maxscriptvars   9999

#maxentityvars {int}
#define a variable list in each entity that can be accessed by index
#use getentityvar(entity, index) and setentityvar(entity, index, value) to use those variables
maxentityvars   9999

#maxindexedvars {int}
#define a global variable list that can be accessed by index
#use getindexedvar(index) and setindexedvar(index, value) to use those variables
maxindexedvars  9999

#maxglobalvars {int}
#define a global variable list that can be accessed by name
#see getglobalvar setglobalvar getlocalvar setlocalvar for details
#the default value is 2048
#If there's no script in the game, just set it to 0, or don't change it unless you know how big it should be
maxglobalvars  9999

alwaysupdate 1
 
Just did the latter with the neo geo edit pak as my base. I think I made a breakthrough?

When I made a scripts folder (with literally nothing in it) and added my scripts.txt file into it. The memory usage suddenly jumped up to 624.336 kb.

Here's my scripts.txt file for reference. Chances are I knew I overdid it but idk which one to reduce or how I could improve this.

Code:
#maxscriptvars {int}
#define a variable list in each script that can be accessed by index
#use getscriptvar(index) and setscriptvar(index, value) to use those variables
maxscriptvars   9999

#maxentityvars {int}
#define a variable list in each entity that can be accessed by index
#use getentityvar(entity, index) and setentityvar(entity, index, value) to use those variables
maxentityvars   9999

#maxindexedvars {int}
#define a global variable list that can be accessed by index
#use getindexedvar(index) and setindexedvar(index, value) to use those variables
maxindexedvars  9999

#maxglobalvars {int}
#define a global variable list that can be accessed by name
#see getglobalvar setglobalvar getlocalvar setlocalvar for details
#the default value is 2048
#If there's no script in the game, just set it to 0, or don't change it unless you know how big it should be
maxglobalvars  9999

alwaysupdate 1

Get rid of all that other than alwaysupdate. Unless you're on a ridiculously old version (we're talking a good ten years back), you don’t need them. It's probably not the issue, but still something to fix.

DC
 
View attachment 10450

update actually: I just saw the usage go up as I began to play the first couple of levels again, so maybe the problem still persists?

Yeah, like I said, the fix above was a separate issue. You have a bad memory leak in your game. Probably a script loop or event somewhere creating variables and not cleaning them, but I'd have no way at all to know exactly where without having the module in hand, so you're just going to have to test like I explained.

DC
 
I just saw the usage go up as I began to play the first couple of levels again
In my tests, even if I add a lot of tasks to clear memory, there's always a small amount that is increased along the playthroughs. So, I think this is normal.
However, same as DC said, I strongly suggest checking your scripts. If not properly optimized, the memory usage can "skyrocket" easily.
I think that 373mb is really a high usage, but better than 1.5gb or 819mb as you mentioned initially.
 
So update. I noticed the skyrocketing suddenly happened when the players transition to another part of the level. Once the level fades out into the next segment, it jumps. Not sure how to narrow it down exactly.

When I checked the log, I did notice something else. This is not the whole log (especially since "openbor_loadsprite" was spewing down the whole file for quite a while), but this is probably (or obviously) an indicator too:


Code:
Warning: 9483 script variants are not freed, dumping...
openbor_loadsprite
openbor_loadsprite
openbor_loadsprite
openbor_loadsprite
openbor_loadsprite
openbor_loadsprite
openbor_loadsprite
openbor_loadsprite
openbor_loadsprite
openbor_loadsprite
openbor_loadsprite
openbor_loadsprite
openbor_loadsprite
openbor_loadsprite
openbor_loadsprite
openbor_loadsprite
openbor_loadsprite
openbor_loadsprite
openbor_loadsprite
openbor_loadsprite
openbor_loadsprite
openbor_loadsprite
openbor_loadsprite
openbor_loadsprite

and, so on and so forth...
 
Last edited:
I think you found the culprit. Now you need to narrow it down.


I use loadsprite in a few scripts.

Here's one of the functions that I made myself so it's probably not perfect, but it is the indicator for when a super move is available:


Code:
//SUPER MOVE INDICATOR
void self = getlocalvar("self");
int mp = getentityproperty(self, "mp");
int hp = getentityproperty(self, "health");
int hpmax = getentityproperty(self, "maxhealth");
void sample = loadsample("data/sounds/superready.wav");
int executed = getlocalvar("executed");
void superbar = loadsprite("data/sprites/superbar.png");

if (executed == NULL()) {
    executed = 0;
}

if (openborvariant("in_level")) {
    int index = getentityproperty(self, "playerindex");
    int mpx;
    if (index == 1) {
        mpx = 265;
    } else if (index == 2) {
        mpx = 400;
    } else if (index == 3) {
        mpx = 570;
    } else {
        mpx = 10;
    }
    if (mp == 100 && hp < (hpmax/2)) {

      void Frame1 = getglobalvar("Frame1");
      void Frame2 = getglobalvar("Frame2");
      void Frame3 = getglobalvar("Frame3");
      void Frame4 = getglobalvar("Frame4");
      void Frame5 = getglobalvar("Frame5");
      void Frame6 = getglobalvar("Frame6");
 drawstring(mpx, 50, 2, "SUPER MOVE READY (D > F > Unique)", 100);
drawsprite(superbar, mpx-20, 50, 9999);

}

    if (mp == 100 && executed == 0 && hp < (hpmax/2)) {
        // Play the sound sample
        playsample(sample, 0, 200, 200, 100, 0);

        // Mark as executed to prevent looping
        executed = 1;

    } else if (mp < 100) {
        // Reset executed state if mp drops below 100
        executed = 0;
    }

    // Save the executed state
    setlocalvar("executed", executed);
}

}
 
Last edited:
Warning: 9483 script variants are not freed, dumping...
wow, this is why I got a OUT OF ERROR when I was playing the game.
And this gives me an idea why I got one of those erros when I used Coco's pile driver - because it relies on variables for that.

Looking at its code, I had an idea:

frame Data/Chars/Coco/backgrab/4.png
@cmd depost 0
@cmd slam 80 2 -1 3 0 0

@cmd clearL

frame Data/Chars/Coco/backgrab/4.png
First, don't use clearL on the same frame of any other script. You will either cancel/clear the variables of said scripts or you won't clear the variables at all.
I always add an extra frame where I put clearL.

Seciond, I would avoid having empty spaces between the lines. The engine will read it anyway, but you can have some issues with editos, like CMT.
 
Unlike the loadsample, loadsprite keeps reloading the same asset infinitely if repeated. In this case you need to put a variable as a limiter.
In the video below I replicated your code format in the updated.c, this way you can see how the memory will skyrocket easily.



Kratus :ninja: me. :P

Loadsprite() bypasses the sprite database check (this is intentional for various reasons). Always load the sprite once, store the pointer, and then free() the sprite when not needed any more. Generally, load when the game starts, and free when shut down. If you don't free(), the engine will take care of it on shutdown, but also complain in the log and that makes your game look unpolished.

In any case, you don't want it in the update cycle, or in any loop, even with the check @Kratus added, because that's wasted CPU cycles on a logic check that usually isn't needed. This also goes for loadsample(). The oncreate() and ondestroy() functions want to be your friend.

DC
 
In any case, you don't want it in the update cycle, or in any loop, even with the check @Kratus added, because that's wasted CPU cycles on a logic check that usually isn't needed. This also goes for loadsample(). The oncreate() and ondestroy() functions want to be your friend.
The only problem with oncreate/ondestroy in the updated.c is that if I clear variables using clearglobalvar/clearlocalvar everytime I pass in the title screen, these events will not run again.
In my case I need to clear/restart many variables when a playthrough is completed or exited, the void main() is the only one that fits. It would be great if there's a way to define when oncreate/ondestroy runs.
At least to free assets, the ondestroy seems to be the best option when closing the engine.

1744147636978.png
 
The only problem with oncreate/ondestroy in the updated.c is that if I clear variables using clearglobalvar/clearlocalvar everytime I pass in the title screen, these events will not run again.
In my case I need to clear/restart many variables when a playthrough is completed or exited, the void main() is the only one that fits. It would be great if there's a way to define when oncreate/ondestroy runs.
At least to free assets, the ondestroy seems to be the best option when closing the engine.

View attachment 10456

The entire point of create/destroy is that it only runs when the script loads/unloads. For update, that's obviously going to be on startup and shutdown. You just happen to have a unique workforce that requires its own solution.

The best way way would be an events that runs when certain screens start. We should be able to add something like that without much trouble.
 
The best way way would be an events that runs when certain screens start. We should be able to add something like that without much trouble.
Yeah, this kind of feature would be amazing. Something like level.c but when entering in the "menu" or "select" screens (something like menu.c or select.c).
 
Back
Top Bottom