Memory allocation issues

micropython

#1

So my question really revolves around instancing and clearing the instances.

For example, I have a class, say, called the Enemy class. I create a list of enemies with it like this:

lvlEnemies = []
...
lvlEnemies.append(Enemy(enemyType, x, y, direction, speed))
...

I then loop over them to update and draw them as such:

for localEnemies in lvlEnemies:
     localEnemies.update()
     ....

…and…

for localEnemies in lvlEnemies:
    localEnemies.draw(screen, localEnemyPos[0], localEnemyPos[1], localEnemies.getDirection())
    ...

Long story short. If I want to remove an instance of an enemy that has been killed, currently I’d do:

enemyId = 0
for localEnemies in lvlEnemies:
    [psuedo code] if player x/y = localEnemies x/y
    thisEnemyId = enemyId
    enemyId += 1

if thisEnemyId != 0:
    del lvlEnemies[thisEnemyId]

Does this method remove only the list entry or does it remove the actual instance too? I ask, as I’ve already hit the memory wall when instancing things, and have had to do alternative things where I only instance some things at the start of the game, then adjust a property in the instance to hide them instead of removing and adding them again for the next level etc…


#2

@jvdw007

I really recommend NOT using dynamic allocation for the enemies. It’s possible to make it work, but I was unable to get the garbage collection (disposal of unused memory items) to work reliably and ran into memory problems later.

The way I solved this:

  1. I use a init function to populate the enemy array in the beginning of the game.
  2. I populate the array up to max enemy number needed
  3. each enemy has a “alive” property which I check to see if the enemy is alive or not
  4. when I need a slot for an enemy, I have a function that goes through the enemy array and simple allocates the new enemy on any “dead” entries in the array

Its not as elegant, yes, but this is how I got completely rid of random memory errors.


#3

Thanks @jonne - I guess I did it right then, ie the “alive” property.
It’s more of a pain to work like that, but at least now I know for future games.

EDIT:
Sorry @jonne - could you or someone respond to my question about clearing the instance, ie, does the

Remove the instance or just the array/list value in the array/list?


#4

The problem is that del just marks it as “garbage” and the garbage collector is supposed to take care of it (= free the memory).

But the problem for me was that I needed to create new bullets and enemies very fast, and I couldn’t rely on the garbage collector to happen on time.

You can manually force the garbage collector to run using:

gc.collect()

But again, I noticed that running gc.collect too often results in a big performance hit. Therefore I only use dynamic allocation for “slow” objects that I create between levels (mines, asteroids and bases) and I use a normal array for “fast” objects that I need to create and delete quickly (enemies, projectiles)


#5

Thanks @jonne.
I spent all morning reworking everything to make it work like that, only to get so convoluted, I got lost in the absolute disastrous state my game got into. So I loaded up my previous version and started again from there, using gc.collect(). Luckily, the places I use it, has no affect on performance and seems to have done the trick, which is great. Still, I’m much more aware of the memory limitations and code things differently now with this in mind, so thanks for the heads-up.