# Memory exhausted



## szcz (Sep 14, 2020)

I'm getting this error, never seen it before. Working on fairly large script, adding new lines somewhere at the beginning on init triggers "memory exhausted", though I can add same lines at the end of init. Also trying to reorganize parts of init code does this. Anyone can shed a light? Is this parser stack overflow 2.0?


----------



## EvilDragon (Sep 15, 2020)

Could be... never saw it either. How big is your ICB? How many variables, arrays and UI controls are declared?


----------



## szcz (Sep 15, 2020)

There are some 37000 lines, 17k lines in init section, 239 variables, 162 arrays, 1256 ui elements declared. Not sure what ICB stands for, if it's Ice Cold Beer, then 0,33 liter. I just found that adding couple of always true if-end if brackets is effective workaround, same as with parser stack error, maybe it's been just renamed in latest build?


----------



## EvilDragon (Sep 15, 2020)

Hahah, ICB is "init callback". And yes, your ICB is too big, you probably need to make it more efficient. A few suggestions:

1. If you have any large lookup arrays, don't define them in init callback, rather load them from NKAs using load_array() mode 2
2. Define ALL your UI controls contiguously in one single block, without any other variable in between, then you can easily create a single UI ID lookup array with a very short loop:


```
for i := 0 to NUM_CONTROLS - 1
    ID[i] := get_ui_id(NameOfFirstUIControl) + i
end for
```

3. Have a master control par array that sets the most important control parameters for all UI controls in a single inlined array. This should considerably reduce the size of init callback.


----------



## szcz (Oct 8, 2020)

Small insignificant update... I've been running into "memory exhausted" message more, using more if(1=1) brackets solves the problem. Tried suggestion no.1, though when measured with KSP_TIMER it looks like loading from nka takes noticeably more time than filling up via script, so I rolled back.


----------



## EvilDragon (Oct 9, 2020)

Loading from NKAs shouldn't worry you in the grand scheme of things (you load things just once in init, when you load NKI or restart audio engine - if you do things properly then you should be using snapshot mode 1 so that init callback is not ran again on every snapshot load). It IS making the init callback shorter though, which prevents you from running into parser overflows. (1=1) is a hack, not a solution. Solution is writing your init callback more efficiently 

If you literally spend most of your init callback setting each individual UI control property in a separate line of code (which I'm thinking is the case here, because not many other things would be the cause of these problems), that is quite inefficient and you should look into doing things as in suggestion no. 2+3.


----------



## szcz (Oct 9, 2020)

So you think that it's a better idea to use more memory for arrays that have no purpose other than making init shorter and make the code less readable than use a 'hack' to work around poor job that parser does?


----------



## EvilDragon (Oct 9, 2020)

Absolutely. And it's actually making things more readable while still being compact, and absolutely fast to edit. Example:






Now count how many more lines of code that would be to set all those parameters one by one (even if you disregard those that are 0). This is simply a massive improvement, and you can go ahead and make instruments with a thousand or more UI controls without ever reaching the parser overflow - because that single array with all control pars the parser counts as a SINGLE line of code, since you're breaking it up with all those ellipses! THIS is where the hugest LOC savings are!


Memory is cheap. Long init callbacks are never a good thing if they can be made way more compact.


I bet with this method your init callback goes from 17k lines to at least 10k lines less, if not more (if you put all the big lookup arrays to NKAs and load them, and hey, even this array can end up being an NKA).


Another method would be using Creator Tools' GUI Designer, this abstracts the UI definition completely from the init callback.


----------



## McSound (Oct 10, 2020)

My jaw's on the floor. Ingeniously! Throwing my code (init section) to trash)


----------



## McSound (Jan 8, 2021)

Mario, but what if I have an array of controls and declare it as "declare ui_label Labels[12]"? Should I add saparate 12 lines in declare CONTROL_PAR section? It seems much shorter if just having "for" loop to assign parameters to all of them. How in general you manage it in that case?


----------



## EvilDragon (Jan 8, 2021)

Ha yeah, if you use UI arrays it gets trickier. Since those get their own UI ID arrays, you should probably handle them in separate loops.


----------



## McSound (Jan 8, 2021)

Thanks for fast responce, ED!


----------



## maxchristensenaudio (May 21, 2021)

Could you elaborate on the picture you shared @EvilDragon ?
I understand what you are achieving by this, just not how exactly you approach it.

In my current script I grouped various UI elements into macro blocks (view.LFO1.L, view.LFO2.L ... , view.LFO1.R etc). It feels like this is now coming to bite me in the butt since I have >200 controls, my memory is also exhausted and I don't think I can implement a master all UI control par array like you did...

I learned about the get_ui_id(control) + i method way late but it also felt risky, since this method relies on the order the controls were declared in.


----------



## EvilDragon (May 21, 2021)

So you can simply move all your macro calls to go one after another so that all your UI controls are declared one after another (provided no other variables are declared in the macros), this would ensure contiguous UI IDs for all UI controls. However if you're using i.e. SublimeKSP's UI arrays, then this creates an additional array, so then this method is a no go in that case.

My approach from the above pic is quite simple: I declare all UI controls in one contiguous block, then declare an array that holds UI IDs, then everything else matches up to that. The CONTROL_PAR array contains values for various control parameters (which you can see in the for loop below what their order is). The only thing I could've done to make it slightly clearer is to use a 2D array, but this is rather old code. So this is a short example how things might look with a few controls:


```
on init
    define NUM_CONTROLS := 3
    define NUM_UI_PARAMS := 15

    declare i

    declare pers ui_menu Channel1
    declare pers ui_menu Mode1
    declare pers ui_slider Tune1 (-3600,3600)

    declare ID[NUM_CONTROLS]

    for i := 0 to NUM_CONTROLS - 1
        ID[i] := get_ui_id(Channel1) + i
    end for

    declare !CONTROL_PIC[NUM_CONTROLS]
    CONTROL_PIC[0] := "my_menu"
    CONTROL_PIC[1] := "my_menu"
    CONTROL_PIC[2] := "my_knob"

    declare !CONTROL_HELP[NUM_CONTROLS]
    CONTROL_HELP[0] := "Help text for Channel menu"
    CONTROL_HELP[1] := "Help text for Mode menu"
    CONTROL_HELP[2] := "Help text for Tune knob"

    declare !CONTROL_AUTO_NAME[NUM_CONTROLS]
    // do the same for automation names etc.

    declare CONTROL_PAR[NUM_CONTROLS, NUM_UI_PARAMS] := ( ...
     48,    2, 98,  18,        0, 0,     0,  0,   0, 0,  0, 0, 0, 0000000H, 0000000H,   { Channel1         } ...
     48,  23, 98,  18,        0, 0,     0,  0,   0, 0,  0, 0, 0, 0000000H, 0000000H,   { Mode1            } ...
     48,  44, 98,  18,        0, 6,     0,  0,   0, 0,  0, 1, 0, 0000000H, 0000000H,   { Tune1            } ...
    )

    { setting up all control parameters }
    for i := 0 to NUM_CONTROLS - 1
        ID[i] -> picture          := CONTROL_PIC[i]
        ID[i] -> help             := CONTROL_HELP[i]
        ID[i] -> automation_name  := CONTROL_AUTO_NAME[i]

        ID[i] -> x                := CONTROL_PAR[i,  0]
        ID[i] -> y                := CONTROL_PAR[i,  1]
        ID[i] -> width            := CONTROL_PAR[i,  2]
        ID[i] -> height           := CONTROL_PAR[i,  3]
        ID[i] -> default          := CONTROL_PAR[i,  4]
        ID[i] -> unit             := CONTROL_PAR[i,  5]
        ID[i] -> mouse_behaviour  := CONTROL_PAR[i,  6]
        ID[i] -> font_type        := CONTROL_PAR[i,  7]
        ID[i] -> textpos_y        := CONTROL_PAR[i,  8]
        ID[i] -> text_alignment   := CONTROL_PAR[i,  9]
        ID[i] -> hide             := CONTROL_PAR[i, 10]
        ID[i] -> allow_automation := CONTROL_PAR[i, 11]
        ID[i] -> show_arrows      := CONTROL_PAR[i, 12]
        ID[i] -> bar_color        := CONTROL_PAR[i, 13]
        ID[i] -> zero_line_color  := CONTROL_PAR[i, 14]
    end for
end on
```


But in all honesty, unless one heavily relies on UI arrays from SublimeKSP, everyone should just use GUI Designer from Creator Tools. It separates the UI definition in a file, which greatly reduces the size of init callback.


----------



## maxchristensenaudio (May 21, 2021)

Ah I see now. I was confused because I couldnt see any strings in your image but you were also doing picture assignments. This makes more sense. Thx for clarifying!


----------

