Navigation

    Fuze Arena Logo
    • Register
    • Login
    • Search
    • Categories
    • Recent
    • Popular
    • Users
    • Groups
    • Help
    • Discord

    Possible memory leak with strings and arrays

    Bug Reporting (FUZE 4 Nintendo Switch)
    6
    9
    766
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • N
      nudibranchkin last edited by Martin

      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.

      1 Reply Last reply Reply Quote 0
      • Martin
        Martin Fuze Team last edited by

        Please try and add i = 0 between the first repeat and the loop. i think this is a bug!

        N 1 Reply Last reply Reply Quote 0
        • N
          nudibranchkin @Martin last edited by

          @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 ^^

          1 Reply Last reply Reply Quote 0
          • L
            Lupinos last edited by

            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(?).

            1 Reply Last reply Reply Quote 0
            • vinicity
              vinicity F last edited by

              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?

              L 1 Reply Last reply Reply Quote 0
              • L
                Lupinos @vinicity last edited by

                @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().

                Gothon 1 Reply Last reply Reply Quote 0
                • spikey
                  spikey F last edited by

                  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.

                  1 Reply Last reply Reply Quote 0
                  • Gothon
                    Gothon F @Lupinos last edited by Gothon

                    @lupinos This program is indeed recursive. The program starts with init() which calls mapgen() which calls genrooms() on the last line which then calls main() 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.

                    L 1 Reply Last reply Reply Quote 6
                    • L
                      Lupinos @Gothon last edited by Lupinos

                      @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

                      1 Reply Last reply Reply Quote 4
                      • First post
                        Last post