Jump to content
Sign in to follow this  
m0nkey

Are local variables destroyed at script termination?

Recommended Posts

Here is a question for someone, assuming I even understand what I am asking lol.

If I exec a script, and that script uses a local variable (ie. _local_v), and I create an object with that _local_v variable (or whatever), is it retained in the memory space of arma and does it retain its parent?

Meaning, if I run script "xyz" once, create an object with _local_v as the handle/reference, and then the script closes (finishes), is the variable destroyed? If I run the same script again, in the same scope and locality, is the reference held in memory?

Which leads me to ask, if it is destroyed, would the work-around be to declare a global and use that, or stick its value (object reference) into an array and then select it later when needed?

One more thing, if I need to use globals, but only for the server, would I have a custom init_server.sqf file that would hold all of my globals? Better question perhaps is what is most efficient? To create a large if (isServer) then {declare variables globally}; or some other method?

Well, enquiring minds do want to know lol.

Share this post


Link to post
Share on other sites

from my experience - and this is not in any way shape or form good authority, i would presume that the local variable is removed from memory once the call to that particular script is complete. I can only assume that it remains in memory whilst a script/function is still using that particular variable. Much like that of a using call - im guessing a variable is create/copied upon calling a function, then anything in side that called function is created and manipulated as required for the life of the function. On the return i would assume that the new variable declared (to hold the return) is enacted and the variable created in the function is removed from memory.

As for the global method/ array holding object - all depends on what you are doing. There is also setvariable that can be used to assist with such calls to information.

For the global on the server - it again all depends on what you are creating, efficiency, and assisting others to read your code. You will have to think about locality later and for JIP when declaring globals and although only for server, will players need to affect them, change them, etc. You got a specific question in mind or senario?

again, take what i said above with a pinch of salt...

Share this post


Link to post
Share on other sites
Here is a question for someone, assuming I even understand what I am asking lol.

If I exec a script, and that script uses a local variable (ie. _local_v), and I create an object with that _local_v variable (or whatever), is it retained in the memory space of arma and does it retain its parent?

Meaning, if I run script "xyz" once, create an object with _local_v as the handle/reference, and then the script closes (finishes), is the variable destroyed? If I run the same script again, in the same scope and locality, is the reference held in memory?

Which leads me to ask, if it is destroyed, would the work-around be to declare a global and use that, or stick its value (object reference) into an array and then select it later when needed?

One more thing, if I need to use globals, but only for the server, would I have a custom init_server.sqf file that would hold all of my globals? Better question perhaps is what is most efficient? To create a large if (isServer) then {declare variables globally}; or some other method?

Well, enquiring minds do want to know lol.

You don't want to overthink it too much mate.

Just use local variables as appropriate (ie; to make your life easier by having pre-determined values you can use later on in your scripts).

I'm pretty confident they are nilled (ie no memory allocation) after the script is finished. If that were not the case then Arma would sooner or later crash out with all the variables of all the scripts being kept in memory and filling up your RAM with variables.

Global are kept in memory however. You can nil them if you like if you are finished with them in your mission. just set a line like: myGlobalVariable = nil;

Personally I wouldn't want to though. That's why you decide to make them global for good reason. :) The Arma engine handles most stuff you can throw at it. You can even do complex geometry calculations in real time and it endures it pretty well.

The main causes of slowdown or stutters in game for me when I'm scripting is as follows:

:icon_evil: Spawning lots of units at roughly the same time

:icon_evil: Changing waypoints for lots of groups at the same time

:icon_evil: Doing large radius searches (like nearestObjects or selectBestPlaces)

:icon_evil: Doing lots of intense string calculations (like BIS_fnc_inString)

A lot of this stuff can be tackled in different ways to mitigate the performance drain, but unfortunately, anything to do with the AI (spawning or managing) is hard work on the CPU. (in my opinion of course). Hope some of that helps you man.

EDIT: If it helps put it in perspective; I read that ACE 2 (for Arma 2) only used 25Mb of memory to run all the scripts it had included, and there's a lot of scripts/functions in ACE :)

Edited by Das Attorney

Share this post


Link to post
Share on other sites

Local vars are nilled on script termination as Attorney mentioned. Running the same script again with the same var would just result in that var being assigned to the second vehicle that spawned. If you absolutely need to save a variable for later you can use setvariable in conjunction with missionNamespace to save the var. Although theres little difference between that and a global variable in single missions.

Share this post


Link to post
Share on other sites

Wow.

@Mikie boy

Nothing specific in mind really. I am intent on sticking with arma3 for the foreseeable future and as I've some years experience with different program languages, I figured I would learn enough to make my missions run as well as possible and to learn best methods. So I just pick something to do, maybe do it differently than an example, and learn by the "school of hard knocks" lol. Thanks for responding!

@Das Attorney

I always overthink things. It is what I do ;)

The question came when I wanted to create a reference to an object because I figured the local was only viable in the thread which it ran. I understand looping and waiting is used by so many scripts that I want to be creative and find ways not to loop/wait when possible but to actually exit the script and call it later (or a different one). Of course that leaves one in the predicament of how to pass a reference when the original is destroyed.

The matter gave me further thoughts because if I were to just use init.sqf, then all clients would recieve the same globals. But if the globals are only needed on server, why have them exposed. That got me thinking, as far as speed and efficiency is concerned, which method of declaring globals in such a case would be best. To use a private init.sqf or perhaps to use a more complicated if (isServer) code block. Thanks for replying!

@tryteyker

That is the crux of my current learning experience - in order to know what vehicle/unit to manipulate, got to have its reference. So storing them is what I am seeking to learn about. I've not used setVariable yet, and not even seen missionNamespace at all. I will though shortly. Thanks for your time!

I don't know whether its good or bad or whether it will even work, but I've got an idea on how to create a runtime spawn with random patrol that does not need a wait or loop to achieve. Set and forget I guess you would say. It would not be the first time I put a ton of research/effort into coding something that just won't work because of underlying factors. But it never fails to teach me more than doing it the way everyone else does lol. There's nothing quite like hammering on an impossible to figure out what is possible...

Thanks so much for the infos!

Share this post


Link to post
Share on other sites

They are not destroyed (unless you set their value to NIL) but they can not be called in other scripts unless the script which called them is still running. If the script ends, the variable is still set at what it was last set, but can't be called unless the script in which it was declared is running.

For simplicity sake, if I need a variable to span multiple script files, I just make it global.

Share this post


Link to post
Share on other sites

Okay. So regardless of whether it is destroyed or not, its no longer of use once the script process that created it ends. I didn't know with all scripts/variables technically belonging to the arma.exe process if it was useable or not.

I got part of what I was working on, working. Did use global variables.

Does anyone know if there is an easier way to work with multi-dimensional arrays that what the wiki says? (is that what people call biki?)

I am used to referencing arrays, even complex ones, but in a much easier fashion than what is presented for arma. Normally if I making controls, like on a form or something, I want to keep the handles in an array, so I can easily mass-manipulate them (like resizing or docking for example) just by stepping through a "controls array". Even when working with .ini files multi-dimensional arrays are very handy.

Not so sure I want to dive into armas md arrays yet lol. Any inside tips to make it more, umm, un-complicated?

BTW, thanks for the answers!

Share this post


Link to post
Share on other sites
They are not destroyed (unless you set their value to NIL) but they can not be called in other scripts unless the script which called them is still running. If the script ends, the variable is still set at what it was last set, but can't be called unless the script in which it was declared is running.

Have you got a source for that? I'd like to have a read through it.

Also that last (bolded) sentence doesn't make a lot of sense to me. If the script ends then how can it still be running?

Edited by Das Attorney

Share this post


Link to post
Share on other sites

Revisiting this question.

This time though I am wondering, is there any benefit to cleaning up large local variables, ie. large _localArrays. Yep, its my anal over achieving tendencies ;) But really, to make the most optimized code, one "should" free up resources no longer needed unless its done automatically.

So, do I _localArray = nil or does this happen when a script terminates? I've not found an official answer yet anyway.

Share this post


Link to post
Share on other sites

Local array's are nilled, just like local vars. If you are really anal then you could:

_localArray = [];
_localArray = nil;

Share this post


Link to post
Share on other sites

@m0nkey:

I'm running loads of scripts/functions in my dynamic sandbox campaign with indexes from local arrays counting into the thousands and think that as long as you don't create any unwanted loopholes, local variables should be the least of your concerns.

As for referencing objects/units in multiple script files global variables are not a good way to go if you want to run the same script for multiple sides.

I was running into huge problems when I wanted my Fire Support System to run on multiple sides, multiple times. You get the idea how global variables won't cut it in that case.

Using setvar/getvar on allunits/vehicles really worked wonders for me especially when spawning in units, afaik it isn't too hard on the cpu aswell.

:icon_evil: Spawning lots of units at roughly the same time

:icon_evil: Changing waypoints for lots of groups at the same time

:icon_evil: Doing large radius searches (like nearestObjects or selectBestPlaces)

:icon_evil: Doing lots of intense string calculations (like BIS_fnc_inString)

A lot of this stuff can be tackled in different ways to mitigate the performance drain, but unfortunately, anything to do with the AI (spawning or managing) is hard work on the CPU. (in my opinion of course). Hope some of that helps you man.

Hey Das,

in case someone is curious for a solution to reduce the performance drop when spawning units/changing lots of waypoints:

Fred41 shared an incredible little snippet that resolved my issues for spawning units.

_AdditionalUnitCreationDelay = ((abs(FPSMAX - diag_fps) / (FPSMAX - FPSLIMIT))^2) * MAXDELAY;

sleep(_AdditionalUnitCreationDelay);

This could probably be used as dynamic delay between waypoint changing too.

As for selectBestPlaces I'm usually running it for the entire map without any significant performance drops.

According to the outstanding guide from ruebe it's important to increase the precision value as you increase the search radius.

This is what I'm currently running with, searching 20km:

_hillhouse = "(1 - houses) * (1 + hills)";
_forest = "(1 + forest + trees) * (1 - sea) * (1 - houses)";
_hill = "(1 - forest) * (1 + hills) * (1 - sea) * (1 - houses)";
_placeArray = [_forest,_hillhouse,_hill];
_randomplace = _placeArray call BIS_fnc_selectrandom;
_randompos = selectBestPlaces [getposATL player, 20000,_randomplace,80,1];
player setpos ((_randompos select 0) select 0);

When I reduce the precision (80) to 40 it's getting noticeably slower, if I take it up to 100 I can even search larger areas without any significant fps drops.

I tested this quite a lot and couldn't point my finger at the difference between precision values (besides performance impact), the found locations were always as expected.

Hope that's of any use for some of you guys.

Cheers

Edited by Grumpy Old Man

Share this post


Link to post
Share on other sites

@Grumpy Old Man

setVariable is what you use rather than arrays? For handles/references? I must not understand the logic.

If I create say 10 units in a group, thats 11 objects. If I give them 3 vehicles, thats 14. If I give that group 1 waypoint that makes 15. If I want to keep track of these handles (thats supposing I needed to reference each unit which isn't like, but this is an example ;) ) other languages would allow me to assign the value of an array as the handle to the object. You are using setVariable when you want a reference?

I am all about learning "best methods", but how are you using setVariable in a way is more "proficient" than arrays? Or do you use setVar in combination with arrays somehow (ie. arr set [count arr,_doo setVaraible ["Doo",123,True]])?

I mean, I can loop through an array with handles and the code is, umm, more concise than having to remember just variable names. (unless you only use them when you want to be specifically referencing variable names).

I've taken the bait Grumpy, lol, any further explanations??

- I've taken the Fred41 spawn delay code and Ruebe's logic and merged them into my hive - they are one.. thanks for those little tidbits btw.

Share this post


Link to post
Share on other sites
@Grumpy Old Man

setVariable is what you use rather than arrays? For handles/references? I must not understand the logic.

If I create say 10 units in a group, thats 11 objects. If I give them 3 vehicles, thats 14. If I give that group 1 waypoint that makes 15. If I want to keep track of these handles (thats supposing I needed to reference each unit which isn't like, but this is an example ;) ) other languages would allow me to assign the value of an array as the handle to the object. You are using setVariable when you want a reference?

I am all about learning "best methods", but how are you using setVariable in a way is more "proficient" than arrays? Or do you use setVar in combination with arrays somehow (ie. arr set [count arr,_doo setVaraible ["Doo",123,True]])?

I mean, I can loop through an array with handles and the code is, umm, more concise than having to remember just variable names. (unless you only use them when you want to be specifically referencing variable names).

I've taken the bait Grumpy, lol, any further explanations??

- I've taken the Fred41 spawn delay code and Ruebe's logic and merged them into my hive - they are one.. thanks for those little tidbits btw.

Like you said, I only use them to identify specific units for scripts that have to run multiple times for multiple units on multiple sides so you don't have loads of global arrays clogging up the memory

I'm still by far not as knowledgeable as I want to be and might be completely in the dark concerning my scripting methods, every day's a learn day, heh

Share this post


Link to post
Share on other sites

Well, I think the proper use for any variable type depends on the concrete situation. Here's what I usually do:

Local

Usually used to store temporary values within a script and to catch incoming parameters of course. In rare cases I define script-only constants or sub-functions with local vars or #define. And I usually prefer to transfer values from global variables into local ones to not accidently overwrite the gobal vars. Be aware of the fact that - if not set to private - local vars might still be accessible for the calling instance even if the actual script should have been finished. Might be related to the thread in which the script is running but I can only guess here, there have been some forum posts stating similar observations.

Global

I use it to save mission specific constants but mostly for referencing objects, like units etc. Most of the time I initialise them on mission start and then restrict my code to reading operations only. In my opinion global vars are the "dirtiest" way of storing values because they can easily be manipulated from anywhere in a mission. If you have a whole system of complex functions and make a mistake by overwriting a global var somewhere in 1000s of lines of code debugging can become a pain in the ass.

Object's Namespace

That's the best way of storing object specific values. Think of a player's money in an MP environment or other player-specific information. It's harder to manipulate these values by accident and you can have the same variable attached to many units with totally different values. For example, some of my scripts add variables to units spawned during a mission. That way I can keep track of units spawned by automated scripts, making debugging easier. Or another example: I have scripts to randomise unit's loadouts and uniforms to create different "factions". The only piece of code in their init line is:

this setVariable ["IP_Faction", "FactionName"]; 

Since init lines run pre-init.sqf I have a generalised "dispatcher" in my init.sqf which loops over all units, reads out this identifier and calls the appropriate "faction-script".

Share this post


Link to post
Share on other sites
Hey Das,

in case someone is curious for a solution to reduce the performance drop when spawning units/changing lots of waypoints:

Fred41 shared an incredible little snippet that resolved my issues for spawning units.

_AdditionalUnitCreationDelay = ((abs(FPSMAX - diag_fps) / (FPSMAX - FPSLIMIT))^2) * MAXDELAY;

sleep(_AdditionalUnitCreationDelay);

This could probably be used as dynamic delay between waypoint changing too.

As for selectBestPlaces I'm usually running it for the entire map without any significant performance drops.

According to the outstanding guide from ruebe it's important to increase the precision value as you increase the search radius.

This is what I'm currently running with, searching 20km:

_hillhouse = "(1 - houses) * (1 + hills)";
_forest = "(1 + forest + trees) * (1 - sea) * (1 - houses)";
_hill = "(1 - forest) * (1 + hills) * (1 - sea) * (1 - houses)";
_placeArray = [_forest,_hillhouse,_hill];
_randomplace = _placeArray call BIS_fnc_selectrandom;
_randompos = selectBestPlaces [getposATL player, 20000,_randomplace,80,1];
player setpos ((_randompos select 0) select 0);

When I reduce the precision (80) to 40 it's getting noticeably slower, if I take it up to 100 I can even search larger areas without any significant fps drops.

I tested this quite a lot and couldn't point my finger at the difference between precision values (besides performance impact), the found locations were always as expected.

Hope that's of any use for some of you guys.

Cheers

Hi mate,

Thanks for the tip on the spawning - I was trying to get something something similar to work but could get the maths right so reverted to the old standby:

sleep 0.5;

;D

I think I've found the issue with the SBP I was using - I'd combined it into a function with bis_fnc_findSafePos and it was actually that that was slowing the game down (which leads back to using nearestObjects).

I've since moved all the nearestObjects code into init, so it takes a while to fire up but is then a lot quicker in game.

You should have a look at the wiki with the new SBP filters that ffur2007slx2_5

posted up - I haven't tried them yet but they look quite useful:

In ArmA3 ver 1.14 Two new expressions are available: waterDepth(0-1) and camDepth(0-1), along with three simple operators: interpolate, randomGen and factor that can be used together with expressions.

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
Sign in to follow this  

×