Pysconian[WIP]

They’re probably implemented with hash tables. A large number of dynamic languages do that.

Static languages have the luxury of just packing all the data fields into a block of bytes and calling that the object.

Making good use of local variables is an optimisation that applies to all languages, dynamic or static.
Local variables will pretty much always end up in registers or on the stack.
Dynamic languages are typically stack based, but they don’t use the stack because that’s needed for VM function calls.
Instead they tend to maintain their own custom stack.

Can you show an example? I do not quite get it.

@Hanski , I am running into real issues with the garbage collector. It doesn’t work. No matter what I try to delete objects, they don’t get deleted fast enough, so the memory leaks kill me. I have to give up dynamic allocation completely

In particular, I am having issues reinitializing the game after player has died. I can’t for the life of me, get rid of old objects

If I, for example use a mechanism like this:

for i in range(0,6):
    newpod = pod.Pods(x,y,z)
    base.pods[i] = newpod
    del newpod

… the newpod instances hardly ever get deleted, leading to running out of memory the next time. the base.pods are already static because of theses issues.

@dir3kt, I think I know now why you stopped on the Bearrrr project.

This should force GC to free memory:

import gc

...
gc.collect()

Does not help at all

edit: is it possible to “print out” the memory usage?

print (“free:”,gc.mem_free())

print('free: '+ str(gc.mem_free()))

Both ways should work.

This is my dilemma. If the player dies, and i try to restart the level, I can’t for the life of me get the pods of the bases cleared:

initgame/start/free: 12704
bases/start/free: 12608
bases/popped/free: 12656
bases/free: 9072
** player dies, initgame is called again **
initgame/start/free: 11648
bases/start/free: 11536
bases/popped/free: 11584
bases/free: 4512 

Found the culprit

This doesn’t do anything:

while(len(bases)):
        bases.pop()
    gc.collect()

Next time I run it, it begins appending more bases, so next time i have 2x the bases, then 3x, then 4x

1 Like

Thank you Hanski,

by talking to you I solved the problem:

initgame/start/free: 10928
bases/start/free: 10848
bases/popped/free: 10896
bases/free: 7456
initgame/start/free: 10928
bases/start/free: 10848
bases/popped/free: 10896
bases/free: 7456
initgame/start/free: 10928
bases/start/free: 10848
bases/popped/free: 10896
bases/free: 7456
initgame/start/free: 10928
bases/start/free: 10848
bases/popped/free: 10896
bases/free: 7456
initgame/start/free: 10928
bases/start/free: 10848
bases/popped/free: 10896
bases/free: 7456 
4 Likes

Quick update. Added my trick music idea (no SD needed).

The idea was to make it loud and noisy, and Ahti, my playtester, already enjoys the game. Music by me btw, made in LMMS

Pretty much only enemy ships missing now that memory issues are solved

Edit: why not original Bosconian sounds? Because I am going through all this effort, so why use someone elses copyrighted stuff. I am using milllisecond timer (inside Python) to loop and mix sounds

6 Likes

That sounds really good!

2 Likes

LMMS :heart_eyes:… I’ve got the full suite or FL Studio, but on linux it is much easier to just grab lmms haha… since I have to use Wine to get my fl studio working.

1 Like

How did you make the music? I mean what instruments?

2 Likes

I found Bosconian themes on some online sequencer web app (google Bosconian music). I changed the note patterns to a different melody but with same key. I exported a midi, installed a .sf2 sound font for FM synthesis, played back from VLC to Audacity using Windows Wasapi as recording device. Put that as wav into LMMS and the rest is default instruments of LMMS

2 Likes

Checking the docs, I think this might have:

while(len(bases)):
	object = bases.pop()
	del object
gc.collect()

If not then you’re probably better off just deleting bases and assigning a new list to it.

If I had to guess, I’d suspect List is implemented as a reference to a block of memory and an index pointing to either the next item or the last item in the list, then pop is implemented by just decrementing the index rather than trying to remove the reference to the item.


This is why I haven’t been getting particularly involved with Python.

Dynamic languages always seem to be easier for people to use at first because they hide away all the details of memory allocation.

However, after a game gets to a certain size the memory starts to dry up and it’s really hard to figure out why precisely for the same reason the language is seemingly easier - because all the details of memory allocation are hidden away.

To compound the problem, dynamic languages tend to eat a lot more memory than statically typed languages because they rely heavily on dynamic allocation, whereas with statically typed languages you can typically avoid using dynamic allocation altogether, or at least keep better control over when it’s used.

In your case it could even be that you’re actually running into heap fragmentation issues depending on how the GC works.
(I.e. whether or not it uses an anti-fragmentation techniques like allocating object pools.)

Ultimately this is all just another example of one of the golden rules of programming:
everything is a trade-off.

Python is easy to get going with for a beginner,
but on an embedded device you’ll hit the ceiling of capability much sooner.

C++ takes more time to understand and get used to,
but it gives very fine control over memory usage,
meaning that it can achieve a lot more than GCed languages.

However, a programmer’s understanding of the inner workings of a language always dictates how effectively they can conserve memory, regardless of language.

4850812

2 Likes

Indeed. And now that I have figured out (somewhat) how the garbage collect works, I am ready to admit I was wrong. The problem was my code, not the uPython gc.

There was one stage in the loading of the level where I appended to a list but forgot to pop. That was the memory leak.

Now, having figured that out and taking care of all my objects, I am running 50 mines, 50 asteroids, 35 pods, 5 bases and 20 projectiles at once, all dynamic instances.

I think uPython is handling it pretty nicely, given the tiny RAM its working with. My poor code was the culprit. Just so that I set the record straight.

1 Like

Great job so far. I wish I was as good as you at coding. :smiley: Working on learning more though.

The way you do music is brilliant.

2 Likes