Possible memory leak with strings and arrays
-
This is a condensed version of a very odd issue I have found:
// create array of strings all containing "a" a = [] for i = 0 to 1000 loop a[i] = "a" repeat loop // add to each string and replace // there should not be an array out of bounds error here because nothing is getting removed or added to the array of strings for i = 0 to len(a) loop a[i] += "a" a[i] = "a" repeat update() repeat
After running this for about one second Fuze will return an array index out of bounds error. Making the length of the string array larger will crash the program faster, and making it smaller lets it run longer, but it still crashes.
The same thing happens when replacing larger arrays with smaller arrays.
-
Please try and add
i = 0
between the first repeat and the loop. i think this is a bug! -
@Martin Thank you I will try this when I have the chance, I've had similar issues with doing the same thing with 2D arrays, and so I will try that too ^^
-
I encountered a similar problem. I`m trying to implement procedual generation to my game. For this I have to run several 'for looops' which save arrays of structures and finally the map array.
Works fine (with the one or other tweak here and there to positioning the rooms), but for some reason every time I run the process (by button press for testing) the memory gets stacked till not enough memory is left and the game crashes due to "Recursion limit exceeded".
Seems like a memory leak to me(?). -
Doesn’t that error message indicate that you may have nested too many loops, rather then a memory leak?
If you switch on the memory overlay, can you see an issue with the memory running out?
-
@vinicity said in Possible memory leak with strings and arrays:
Doesn’t that error message indicate that you may have nested too many loops, rather then a memory leak?
If you switch on the memory overlay, can you see an issue with the memory running out?
Yes. With every mapgen-process the memory becomes less.
And I don't even use any textures yet. I'm just storing data of numbers in structures and arrays.
As I said. The first cycle starts well with free memory of about 1300MB with second cycle it drops down to 900(!)MB, third cycle leaves me 430MB and then BAM!x=30 y=17 array map[x][y] init() function init() mapgen() returnvois function main() loop clear() c=controls() for x=0 to len(map) loop for y=0 to len(map[0]) loop print(x,y,map[x][y]) repeat repeat if c.a then mapgen() endif update() repeat return void //MAP GENERATION function mapgen() //fills array with 0 (walltiles) in mapwidth and height for x=0 to len(map) loop for y=0 to len(map[0] loop map[x][y]=0 repeat repeat genrooms() return void //ROOM GENERATION & PLACEMENT function genrooms() fmax=5 //max number of tries to fit a room rmax=4 //max number of rooms on map wmax=6 //max width of a room loop r=rndroom(wmax) //function which generates a room if placeroom(r) then //returns true if room placed rmax-=1 else fmax-=1 wmax=max(wmax-1,3) endif if rmax <=0 or fmax<=0 then //breaks loop if cond met break // might change this to while loop, I guess endif repeat main() //returns to main loop return void function rndroom(wmax) _w=3+floor(rnd(wmax-2)) //random width of room hmax=max(35/_w,3) //35=max tiles of a room _h=3+floor(rnd(hmax-2)) r=[.x=0,.y=0,.w=_w,.h=_h] //room with default x/y pos. return r function placeroom(r) i=0 array cand[i] //possible locations for room struct c int x int y int w int h endstruct for _x=0 to len(map)-r.w loop for _y=0 to len(map[0])-r.h loop if roomfit(r,_x,_y) then //tests if room fits on map cand[i]=[ .x=_x, .y=_y ] //stores the location in array i+=1 else exec=false //returns false if room not fits endif repeat repeat if i==0 then exec=false //returns false if no cand is set endif c=cand[rnd[i]] //chooses a rnd position from cand r.x=c.x r.y=c.y for _x=0 to r.w loop for _y=0 to r.h loop map[_x+r.x][_y+r.y]=1 //sets roomtiles to 1 repeat repeat exec=true return exec function roomfit(r,x,y) fits=false for _x= 0 to r.w loop for _y=0 to r.h loop if map[_x+x][_x+y]==0 then fits=true else fits=false break //breaks the loop as soon as room does not fit endif repeat repeat return fits
I know, that it needs a little tweaking here and there. It does merge the rooms from time to time. But still I do not see, why the memory gets less with every mapgen().
-
If you use x and y in for loops in the mapgen() function, better not declare them outside of the main loop, which makes them gobal. I think they interfere afterwards.
-
@lupinos This program is indeed recursive. The program starts with
init()
which callsmapgen()
which callsgenrooms()
on the last line which then callsmain()
with the comment//returns to main loop
.main()
has a normal game loop with the block:if c.a then mapgen() endif
Anytime you press the 'A' button, these functions will be called in a recursive loop that builds up the stack until it runs out of space, and Fuze doesn't have all that much stack space for recursion either.
Something like this might work in a 'functional' programming language. Such languages often optimize 'tail recursive' calls to use no stack space in order to support recursive looping. Sometimes these languages even don't even have non recursive loops implemented.
What you wan't to do is let functions reach the
return
statement at the end of the function. Program execution will then resume from the place the function was called from. You can make a call to the function you want to run next there, rather than from inside the other function. Ex:x=30 y=17 array map[x][y] init() main() function init() mapgen() genrooms() return void function main() ... if c.a then init() endif ... return void function mapgen() ... // genrooms() <- delete this line return void function genrooms() ... // main() <- delete this line return void
This is the biggest problem I see atm. I think you may also want to compare the state of the button 'A' with its previous value so that
mapgen()
is called only on the frame after the button is pushed down. The way it is written now, it will be called every frame as you continue to hold it down. -
@gothon Oh man! That worked perfectly. Thank you very much. Did not know that.
I converted the code from Pico 8 (Lua programming language), so you are probably right with your guess. haha
Now it runs like charme. <3