Accessors

T

ThePropagation

Guest
Hi, I looked at the manual about accessors, and is there an instance where I shouldn't use them? I've been using the proper accessors in all my arrays and ds_list to eliminate memory leaks, was that the right thing to do? Every instance of an array where brackets are used I've inserted an accessor. Is this right?
 

samspade

Member
It isn't wrong, but it won't eliminate memory leaks. Memory leaks are caused by not destroying ds_* or various other things (like surfaces). Using an accessor or using the built in gml functions won't change or even affect that. Also, there's no point in using the array accessor outside of a script. You can, it just doesn't do anything different than normal. Using it inside of a script is only necessary when setting a value, although again it won't cause an error to do it otherwise. And in fact because of the way gml handles arrays passed to a script, sometimes you don't want to use the accessor on an array because you might want it to copy.

I go back on forth on whether or not to use accessors. They are absolutely necessary in only one case - and that is for arrays inside of a script when you don't want the script to copy an array. Otherwise they are merely shortcuts for less typing. And in exchange for less typing you get possibly less readable code. But they are so common it is like using i or x or y, you're very unlikely to forget what they mean.

In short, use them if you find them helpful, but they won't prevent memory leaks.
 
T

ThePropagation

Guest
I thought not using accessors made memory draining array copies, I made a persistent object that deletes my ds_list and all particle effects and the particle system when the game ends, is there anything else I need to do to?
 

samspade

Member
Arrays are garbage collected and can't cause a memory leak. As long as there is no reference to an array, it'll be removed automatically. When you set the value of an array that has been passed into a script like this:

Code:
var _array = argument0;
_array[0] = some_value;
GM copies the array. This doesn't create a memory leak but it might not be very performant. In general with arrays passed into a script:

Code:
var _array = argument0;

///_array will no be a copy of the array passed into the script
_array[0] = some_value;

///will directly modify the array passed into the script
_array[@ 0] = some_value;

///not wrong but doesn't do anything different
some_value = _array[0];
some_value = _array[@ 0];
Using the @ accessor for arrays outside of a script is the same as not using them. In other words the only time you need to use the array accessor is when you have passed an array into a script and want to modify (not read) the array inside of the script without copying it.

There is, as far as I know, no difference between using data structure accessors or using the GML functions. It is pure convenience.

You could theoretically handle deleting lists with some type of persistent object, but it would be hard to do correctly. The best way to delete data structures really depends on what you're doing with them, but the following two rule will cover most situations:
  • destroy the data structure in the same 'place' you created it. So, if it is an instance variable, use the cleanup event of the object that is creating it. If it is a local variable in an event or script destroy it at the end of the event or script it is in (take special care with scripts and events whenever you are using keywords like return, exit, break, continue or anything that would end the event or script immediately). If it is a global variable, you probably don't need to destroy it as presumably you would want it in existence for the entire game (if not, it probably shouldn't be global).
  • after assigning a data structure to a variable never assign anything to that variable again.
Both of the above rules can be broken, but if you're just learning how data structures work, you probably shouldn't. The one main exception to the above is lists and maps stored inside eachother and marked as such, but if you aren't using the JSON format or that doesn't mean anything then you're safe to ignore it.
 

TsukaYuriko

☄️
Forum Staff
Moderator
Not using accessors implies copy-on-write. This means that if you copy one array reference to a secondary variable, a clone of it is created if, and only if, you write to it, at the exact moment you write to it the first time.

Using accessors disables the copy-on-write behavior and instead always uses the original array.


Note that accessors are neither a way to avoid nor a way to cause memory leaks. It's how you use arrays with multiple references that determines whether you create copies or not. At the point where you have a "memory leak" from that, you have all sorts of other problems to deal with that go way beyond a simple memory leak, since you'll now have two split copies of an array, both of which contain data you'd rather have in both. That aside, the memory leak-like effects from this are minimal due to garbage collection, as mentioned by @samspade.


Data structures never copy on write, and accessors are merely shorthands for the sake of convenience for them.
 
T

ThePropagation

Guest
So, I destroy my ds_list and my particle system and all of the particle types on game end, and I've put accessors in every array usage just in case, is there anything else I need to do to stop any possible memory leak? I don't have any surfaces, ds_maps or grids, no ini files left open or anything like that. Does anything else cause memory leaks? My game still lags after I've played it a while.
 

TsukaYuriko

☄️
Forum Staff
Moderator
Lag is not the result of memory leaks. It's an indicator of you executing more code than your hardware can handle. Use the profiler in debug mode to track down what's eating up most of the performance, report back to us with the offending code and we can help you figure out how to optimize it.
 

Joe Ellis

Member
The lag will be coming from something else.
It could be coming from how many times you're reading from ds_lists and arrays per step. And if you use the @ accessor to write to an array it's alot slower than not using it. But you can only really not use the @ accessor when the array is created in the current script, otherwise it makes a copy, which is fine as long as you make sure you put the copied version into the variable the original was holding, which is normally pretty awkward.
 

TsukaYuriko

☄️
Forum Staff
Moderator
But you can only really not use the @ accessor when the array is created in the current script, otherwise it makes a copy, which is fine as long as you make sure you put the copied version into the variable the original was holding, which is normally pretty awkward.
Since there's already an aura of paranoia in this topic, allow me to clear this up: This is only a problem when two active references to the array exist. When you have a single reference, even if a copy was made, the original would fall out of scope and be garbage collected.

Having a reference to an array in instance A and also referencing it in instance B counts as two references, as long as both instances exist. I see no logical reason why this should ever be the case instead of just storing the array in a central object and referring to it through that, though.
Creating a script in an array, returning it and assigning it to a variable counts as one reference. This is the case even if the array was being stored in a local variable inside of the script, as that has already fallen out of scope by the time the script returns.

If you have more than one active reference to a data structure that should be central, you'd have way bigger problems than memory leaks. Those would make themselves known long before memory leaks would.
 

Joe Ellis

Member
But usually when you use the @ accessor you're only editing one or two values in the array at a time, which is faster than not using it, cus if you don't it makes it copy the whole array unnecessarily. You should ideally use the @ accessor apart from in the script the array is created in, and try to set as many "less likely to change often parts" in that script. Not that it really matters most of the time. It only really makes a difference when your dealing with thousands of vertices or something
 

Joe Ellis

Member
Also referencing an array doesn't make it copy it, writing to it does. Once you write to it without using @, it makes a new copy of it that only exists in that script, which is incredibly unreliable if you've got hundreds of arrays containing other arrays. @TsukaYuriko Have you dealt with this? Cus the thing your talking about is completely out of the question once you put arrays in arrays. (Which for using arrays properly, this is an essential part)
It does swap the new copy with the original but only in the instance that created it, which ends up completely irrelevant. The instance will create say the root array, then other ones inside it. But several others could get made in potentially all instances in the game depending which one calls a certain script. So the thing about it returning the new copy to the instance ends up with no relevance or use at all, and none of the parts that really need it will have had it delivered automatically.
 

Yal

🐧 *penguin noises*
GMC Elder
As with all programming issues, you can make this much easier if you use the proper coding conventions. Either always use [@] and build all your code around scripts editing arrays in-place, or never use it and build your code about returning new arrays (of transient or permanent nature as required).
 
Top