Issues With The Immix Garbage Collector

Hi,

I’ve been struggling with the Immix garbage collection for several months now. I have my game set up to record inputs, player position, and other such things for a replay system, which is how I discovered the issue. After doing a single run, I can run the replay repeatedly, the only interruption being the title screen and replay selection screen in between replays. However, the longer I send the game through a loop like this, the worse things get: drawing events start to render as giant black boxes, the framerate drops, and eventually, the game crashes with “Memory Exhausted!” printed in the log. I’ve optimized numerous things to use less memory, but I simply can’t figure out how to combat this.

How can I get around and avoid the “Memory Exhausted!” error for the garbage collector?

Please ask questions: I’ve spent a very long time on this problem, and there’s a ton of information on it, but I’m hardly sure where to start.

Thanks!

Forgive me if I’m not following, but it kinda sounds as if you have a code issue on your end which is, well, building objects until you are out of resources. Doesn’t sound like GC issue, but the opposite… Like you’re preventing things from being gc’d bc of hard references and the like. Are you disposing of objects once you know they aren’t needed?

Interesting. I hadn’t thought of that angle yet: the engine I’m using generally frees unused objects automatically, but I set up a custom class to render my bullets, since I need a multitude, which most likely doesn’t do that. Is there a specific function that can free objects, or is that also custom coded?

Typically, GC handles things deemed safe to remove. But your situation seems to at least suggest you may be retaining references to perhaps your many bullet instances in a way that prevents the GC from doing its job… preventing it from knowing it’s safe to remove. So, u continue to allocate memory until some crucial threshold.

If you create a bunch of things that you expect to be cleaned up by the GC, make sure things u intend to be still alive don’t continue to reference those things. Those sorts of references make it wisely untouchable by the GC. If that sounds like what’s going on, then once a bullet or whatever is done, then set any prop that might reference it to null. Let me know if that helped.

I’ve been looking at my code, and I can’t seem to find anywhere that would refer to a bullet after it’s been finished with. Each bullet is added to a list when it’s created, but in every case that it’d be killed, it’s removed from that list.

Is there any way to count how many instances of a class exist at any one time? Perhaps this isn’t my issue.

You could loop through the displayList and use Std.isOfType with something like this…

        var n:Int = numChildren;
        while (n-- > 0) {
            var inst = getChildAt(n);
            if (Std.isOfType(inst, BulletClassOrWhatever)) numBullets++;
        }
        trace(numBullets);

If you target HTML5, you can use the browser developper tools to take snapshots of used memory and compare them to identify objects that don’t get removed whereas they should.

1 Like

I set up that test with a couple differences: the bullets use the Tilemap class, so they aren’t actually added to the display list, so I had to count the tiles, but it looks like the bullets are always removed.

I should probably mention that crashing generally occurs when switching between scenes, or quite soon thereafter.

I’m also targeting Desktop, unfortunately, so I can’t try the browser profiler idea.

I agree with intoxopox : your issue sounds like a memory leak, not a GC issue (I’ve had a real issue with GC on desktop where it would crash with “read access violation”)

On desktop you can use hxScout as a profiler, you should be able to see which object(s) never get garbage collected and investigate from there. It might be something you’re not even thinking about (happened to me) :slight_smile:

https://hxscout.com/
I never managed to get it to work with Starling but regular OpenFL worked last time I tried, make sure to follow the instructions as you need to enable telemetry for it to work.

Also if you are using Map on desktop make sure you clear them as they don’t have weak keys

“Also if you are using Map on desktop make sure you clear them as they don’t have weak keys” Absolutely! Additionally, if you have String maps that you iterate over, they end up being Dynamic on cpp target which can cause some unexpected GC behavior in some corner cases, not to mention poor performance.

1 Like

Interesting ! Didn’t know that, thanks for the info

So, I think I’ve figured out the issue: in my engine, I was tinting an image to give it a sepia effect, but it turns out that somehow in my specific circumstances, applying an effect to an image breaks the entire game. Simply removing the effect and settling for something else seems to have fixed the issue.

Thanks for the help though: I’ve been able to optimize a few things a little further.

2 Likes

@Akemi - just out of curiosity - what is ‘Immix’ actually? The title of your game? :smiley:
Any screenshots you could share?

It’s actually the type of garbage collector my engine uses: https://www.cs.cornell.edu/courses/cs6120/2019fa/blog/immix/

I assumed it was part of OpenFL, or that at least the basic principles would translate.