SOLVED Getting ds_grid_resize to work without memory allocation error

Heya,

So I have a series of global grids to which I add rows, and delete rows by resizing the grid. The adding is done by a script which uses the name of the global grid to which entries must be added. My problem is, if I keep adding, then resizing the grid (to simulate row deletion), I eventually get a memory allocation error, specifically at the grid resizing part. Note that the global grids are never meant to be destroyed at any time.

Relevant code for a cursor object that adds entries to a target global grid (global.grid_ext_b[0] in this case):

Step event (the only real relevant parts here are the script call for scr_grid_set_player and ds_grid_resize):
GML:
if myid.team_phase == 1
        {
        if type == 0 //SELECTOR
            {
            if complete_selection != true
                {
                if keyboard_check_pressed(global.k_lt) //add selection
                    {
                    if avail == true
                        {
                        if can_ent == true
                            {
                            can_ent = false
                            alarm[5] = can_ent_rt
                            scr_snd_cre_obj(global.snd_menu_enter)
                       
                            if myid.arc_pool_blue_curr < global.pool_slots_blue_1
                                {
                                if myid.arc_pool_blue_curr == 0
                                    {global.player_a_t = myid.crs.targ}
                               
                                myid.arc_pool_blue_curr += 1
                           
                                var t_crs = myid.crs.targ //Refer to SELECTOR's targ
                           
                                //*add to *grid
                                ds_list_add(global.pool_list_blue_1,
                                global.ar_arc[t_crs, 0]
                                )
                           
                                //ADDING PART
                                scr_grid_set_player(myid.crs_team, global.grid_ext_b[0])
                                }
                       
                            with (myid.crs_team)
                                {
                                if x_pos < (global.solo_team_max - 1)
                                    {
                                    //add selection
                                    base_t.t = myid.crs.targ
                               
                                    //move forward
                                    x += myid.grid_dist_x
                                    x_pos += 1
                                    }
                                else if x_pos == (global.solo_team_max - 1)
                                    {
                                     //final selection - add, but don't move forward
                                    base_t.t = myid.crs.targ
                               
                                    global.nextroom = room_arc_ladder
                                    alarm[2] = delay //delay, then room ladder
                               
                                    complete_selection = true
                                    allow = 0
                                    with(myid.crs) {allow = 0; complete_selection = true}
                               
                                    }
                                }
                            }
                        }
                    }
               
                else if keyboard_check_pressed(global.k_hv) //roll-back selection
                    {
                    if can_ent == true
                        {
                        can_ent = false
                        alarm[5] = can_ent_rt
                   
                        with (myid.crs_team)
                            {
                            //roll back
                       
                            scr_snd_cre_obj(global.snd_menu_arc_desel)
                       
                            if base_t.t > - 1//x_pos >= 0
                                {
                                ds_list_delete(global.pool_list_blue_1,
                                x_pos
                                )
                                myid.arc_pool_blue_curr -= 1
                                base_t.t = - 1
                           
                                //*DELETING PART// remove / *delete from grid
                                //var grid_ext = global.grid_ext_b[0]; <-- local var can lead to pointer being missed, causing memory allocation error
                                ds_grid_resize(global.grid_ext_b[0], ds_grid_width(global.grid_ext_b[0]), ds_grid_height(global.grid_ext_b[0]) - 1)

The adding to grid script (scr_grid_set_player):

Code:
//Add to grid by players' actions, namely in char select screens
/// @param adding_cursor
/// @param grid_ext[x]


var adding_crs = argument[0] // //Refer to cursor that's being used to add chars to the grid. Can be myid.crs_team or myid.crs only, depending on game mode

var grid_ext = argument[1] //the target grid, global.grid_ext_b[0] e.g.
//add additional args later

if global.gmode == "solo"
    {
    var solo_pos = 0
    ds_grid_resize(grid_ext, ds_grid_width(grid_ext), solo_pos + 1);
                       
    ds_grid_set(grid_ext, 0, solo_pos, myid.crs.targ) //t value
    ds_grid_set(grid_ext, 1, solo_pos, global.ar_arc[myid.crs.targ, ar_arc.name_add]) //name "g90" e.g.
    ds_grid_set(grid_ext, 2, solo_pos, global.ar_arc[myid.crs.targ, ar_arc.rank]) //rank
    ds_grid_set(grid_ext, 3, solo_pos, 0) //pal indx
    ds_grid_set(grid_ext, 4, solo_pos, 0) //pal spr
    ds_grid_set(grid_ext, 5, solo_pos, 0) //pool - adjust in accordance to currently selected pool for which chars being added - case switch may be needed
    ds_grid_set(grid_ext, 6, solo_pos, solo_pos) //slot
    ds_grid_set(grid_ext, 7, solo_pos, "player") //control type
    ds_grid_set(grid_ext, 8, solo_pos, 0) //player#
    }
else
    {
    ds_grid_resize(grid_ext, ds_grid_width(grid_ext), adding_crs.x_pos + 1);

    ds_grid_set(grid_ext, 0, adding_crs.x_pos, myid.crs.targ) //t value
    ds_grid_set(grid_ext, 1, adding_crs.x_pos, global.ar_arc[myid.crs.targ, ar_arc.name_add]) //name "g90" e.g.
    ds_grid_set(grid_ext, 2, adding_crs.x_pos, global.ar_arc[myid.crs.targ, ar_arc.rank]) //rank
    ds_grid_set(grid_ext, 3, adding_crs.x_pos, 0) //pal indx
    ds_grid_set(grid_ext, 4, adding_crs.x_pos, 0) //pal spr
    ds_grid_set(grid_ext, 5, adding_crs.x_pos, 0) //pool - adjust in accordance to currently selected pool for which chars being added - case switch may be needed
    ds_grid_set(grid_ext, 6, adding_crs.x_pos, adding_crs.x_pos) //slot
    ds_grid_set(grid_ext, 7, adding_crs.x_pos, "player") //control type
    ds_grid_set(grid_ext, 8, adding_crs.x_pos, 0) //player#
    }
I'm aware of the need for manually deleting local vars containing data structures since GMS lacks the garbage collection needed for this. However, when I tried the following in the above script:

Code:
var adding_crs = argument[0] // //Refer to cursor that's being used to add chars to the grid. Can be myid.crs_team or myid.crs only, depending on game mode

var grid_ext = argument[1] //the target grid, global.grid_ext_b[0] e.g.
//add additional args later

if ds_exists(grid_ext, ds_type_grid)
{
if global.gmode == "solo"
    {
    var solo_pos = 0
    ds_grid_resize(grid_ext, ds_grid_width(grid_ext), solo_pos + 1);
                       
    ds_grid_set(grid_ext, 0, solo_pos, myid.crs.targ) //t value
    ds_grid_set(grid_ext, 1, solo_pos, global.ar_arc[myid.crs.targ, ar_arc.name_add]) //name "g90" e.g.
    ds_grid_set(grid_ext, 2, solo_pos, global.ar_arc[myid.crs.targ, ar_arc.rank]) //rank
    ds_grid_set(grid_ext, 3, solo_pos, 0) //pal indx
    ds_grid_set(grid_ext, 4, solo_pos, 0) //pal spr
    ds_grid_set(grid_ext, 5, solo_pos, 0) //pool - adjust in accordance to currently selected pool for which chars being added - case switch may be needed
    ds_grid_set(grid_ext, 6, solo_pos, solo_pos) //slot
    ds_grid_set(grid_ext, 7, solo_pos, "player") //control type
    ds_grid_set(grid_ext, 8, solo_pos, 0) //player#
    }
else
    {
    ds_grid_resize(grid_ext, ds_grid_width(grid_ext), adding_crs.x_pos + 1);

    ds_grid_set(grid_ext, 0, adding_crs.x_pos, myid.crs.targ) //t value
    ds_grid_set(grid_ext, 1, adding_crs.x_pos, global.ar_arc[myid.crs.targ, ar_arc.name_add]) //name "g90" e.g.
    ds_grid_set(grid_ext, 2, adding_crs.x_pos, global.ar_arc[myid.crs.targ, ar_arc.rank]) //rank
    ds_grid_set(grid_ext, 3, adding_crs.x_pos, 0) //pal indx
    ds_grid_set(grid_ext, 4, adding_crs.x_pos, 0) //pal spr
    ds_grid_set(grid_ext, 5, adding_crs.x_pos, 0) //pool - adjust in accordance to currently selected pool for which chars being added - case switch may be needed
    ds_grid_set(grid_ext, 6, adding_crs.x_pos, adding_crs.x_pos) //slot
    ds_grid_set(grid_ext, 7, adding_crs.x_pos, "player") //control type
    ds_grid_set(grid_ext, 8, adding_crs.x_pos, 0) //player#
    }

ds_grid_destroy(grid_ext)
grid_ext = undefined;
}
The script then throws a "Data structure with index does not exist." error.

I'm probably doing this the wrong way. Could someone help point out the correct approach?

Thanks in advance.
 
Last edited:

Roldy

Member
I'm probably doing this the wrong way. Could someone help point out the correct approach?
I have no idea what you are trying to accomplish, but the above code is probably not the best way to do it. But as for the specific ds_grid_resize problem you should post exactly what error you get.

I eventually get a memory allocation error,
Post the exact error message.
 
Thank you for the reply. I'm basically just trying to add and delete rows in a grid. Since there is no row deletion function in GMS, I figured grid_resize would do.

Error messages as follows:

1) For the actual memory allocation one:
GML:
___________________________________________
############################################################################################
FATAL ERROR in
action number 1
of  Step Event0
for object omenu_arc_crs:

Memory allocation failed: Attempting to allocate 4294967152 bytes
at gml_Object_omenu_arc_crs_Step_0 (line 318) -                                     {ds_grid_resize(global.grid_ext_b[0], ds_grid_width(global.grid_ext_b[0]), ds_grid_height(global.grid_ext_b[0]) - 1)}
############################################################################################
--------------------------------------------------------------------------------------------
stack frame is
gml_Object_omenu_arc_crs_Step_0 (line 318)
2) When applying the grid destroy solution, if the local variable holding the grid name is destroyed:

Code:
___________________________________________
############################################################################################
ERROR in
action number 1
of  Step Event0
for object omenu_arc_crs:

Data structure with index does not exist.
at gml_Script_scr_grid_set_player (line 35) -     ds_grid_resize(grid_ext, ds_grid_width(grid_ext), adding_crs.x_pos + 1);
############################################################################################
--------------------------------------------------------------------------------------------
stack frame is
gml_Script_scr_grid_set_player (line 35)
called from - gml_Script_vm_gml_thread_exec_slice_with2 (line 3) -        return script_execute(argument[0],l_w[l_i],l_w[l_i+1]);
called from - gml_Script_gml_thread_exec (line 757) -                                                                l_v1=(l_n<81?script_execute(g_vm_gml_thread_exec_slice_funcs[l_n],l_o,l_w1,l_k):vm_gml_thread_exec_slice_error());
called from - gml_Script_live_call (line 34) -                                    gml_thread_exec(l_th1);
called from - gml_Object_omenu_arc_crs_Step_0 (line 3) - /*t*/if (live_call()) return live_result;
 

Nidoking

Member
ds_grid_destroy(grid_ext)
grid_ext = undefined;
Well, this is just wrong and leads me to believe that you don't understand what the grid_ext variable is actually doing. It's just the index of a grid that exists in memory. If you destroy the grid, the grid is destroyed - it no longer exists, so attempting to reference it in the future will fail.

I don't think there should be a problem with repeatedly resizing the same grid, but maybe you're leaking grids this way or creating new ones instead of resizing the old ones. How big do these grids get? There's only so much memory available.
 
My initial understanding was that every time I set var grid_ext = argument[1] (i.e. the grid), I was causing a leak. This is why I thought the ds_grid_destroy(grid_ext) line would work. But this is obviously not the case since, as you've mentioned, the actual grid gets destroyed, and also the memory allocation error only pops up when the ds_grid_resize function is run, and never when that script is executed (in the testing I've done thus far).

Also, in that code above, only that one grid (global.grid_ext_b[0]) is being manipulated, and it can only hold a maximum of 5 rows with 9 columns. Only numbers are being held in those grid positions. Surely this should not be so taxing with respect to memory usage? I'll probably try some other way to manipulate the grid (adding + resizing), and see if that helps.
 

Roldy

Member
You
Surely this should not be so taxing with respect to memory usage?
No it most likely is that you have logical errors. Look at the size of bytes you are trying to request: 4294967152

That is exactly 144 below 2^32. You have 9 columns in your grid. 144/9 = 16.

When you are resizing your grid you are miscalculating the math for the grid row count. Where? I don't know, your code is too messed up to read. But that is most likely what is happening.

Example:

GML:
a = ds_grid_create(1,1);

ds_grid_resize(a, ds_grid_width(a), ds_grid_height(a) -1);
ds_grid_resize(a, ds_grid_width(a), ds_grid_height(a) -1);  // Here I tried to resize the grid to a 'negative' number of rows. This rolls the row count over to the high end of 2^32
The above code will trigger the same error trying to allocate: 4294967280 bytes

You are resizing and 'deleting' too many rows.
 
Last edited:
You


No it most likely is that you have logical errors. Look at the size of bytes you are trying to request: 4294967152

That is exactly 144 below 2^32. You have 9 columns in your grid. 144/9 = 16.

When you are resizing your grid you are miscalculating the math for the grid row count. Where? I don't know, your code is too messed up to read. But that is most likely what is happening.

Example:

GML:
a = ds_grid_create(1,1);

ds_grid_resize(a, ds_grid_width(a), ds_grid_height(a) -1);
ds_grid_resize(a, ds_grid_width(a), ds_grid_height(a) -1);  // Here I tried to resize the grid to a 'negative' number of rows. This rolls the row count over to the high end of 2^32
The above code will trigger the same error trying to allocate: 4294967280 bytes

You are resizing and 'deleting' too many rows.

Thanks for that example. In particular, this part:

GML:
// Here I tried to resize the grid to a 'negative' number of rows. This rolls the row count over to the high end of 2^32
So a grid rolling back to -1 rows and below will cause the count to become unstable? Definitely did not know that.

I've applied the following fix:

Code:
if ds_grid_height(global.grid_ext_b[0]) > 0
   {ds_grid_resize(global.grid_ext_b[0], ds_grid_width(global.grid_ext_b[0]), ds_grid_height(global.grid_ext_b[0]) - 1)}
   else
   {ds_grid_resize(global.grid_ext_b[0], ds_grid_width(global.grid_ext_b[0]), 0)}
Even after a few minutes of resizing the grid repeatedly, no memory allocation error.

I assume though that there is no leak as previously believed, but rather simply the grid reaching -1 rows that was causing the problem. Still, might be useful to mark this in case of a grid-related memory leak.

Thank you all for the input needed in solving this issue!
 
Last edited:

Roldy

Member
So a grid rolling back to -1 rows and below will cause the count to become unstable? Definitely did not know that.
It has to do with how negative numbers are represented in binary. GML does not explicitly distinguish between signed and unsigned integers and uses the single Real data type. However, some things under the hood definitely do treat some Reals as unsigned.

This wasn't the cause of your problem. Your problem was caused by trying to 'delete' more rows than there were. The integer roll over was just the symptom. A symptom that made it easy to track down the problem.
 
Ah I see. Granted I should have accounted for going below 0 from the get go (the way it was setup didn't supposedly require doing so), but I wasn't getting any errors initially until I mindfully tested that part out a few times. I assumed GMS would simply throw an out of bounds error or something similar.
 
Top