• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[Solved] When to null a variable?

Status
Not open for further replies.

Uncle

Warcraft Moderator
Level 63
Joined
Aug 10, 2018
Messages
6,456
Hello, I was reading about leaks and I didn't quite fully grasp when I should null a Unit variable and other Object variables.

Here are some examples of what I'm currently doing:

  • Example 1
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Animate Dead
    • Actions
      • Set TempUnit[0] = (Casting unit)
      • Unit - Set life of TempUnit[0] to 100.00%
      • Set TempUnit[0] = No unit

  • Example 2
    • Events
      • Time - Every 1.00 seconds of game time
    • Conditions
    • Actions
      • Set TempPoint[0] = (Center of (Playable map area))
      • Unit Group - Pick every unit in (Units within 500.00 of TempPoint[0]) and do (Actions)
        • Loop - Actions
          • Set TempUnit[0] = (Picked unit)
          • Unit - Set life of TempUnit[0] to 100.00%
          • Set TempUnit[0] = No unit
      • Custom script: call RemoveLocation (udg_TempPoint[0])
  • Example 3
    • Events
      • Time - Every 0.03 seconds of game time
    • Conditions
    • Actions
      • Set Poseidon_TWElapsedTime[Spell_Array] = (Poseidon_TWElapsedTime[Spell_Array] + 0.03)
      • Set TempPoint[0] = (Position of Poseidon_TWDummy[Spell_Array])
      • Special Effect - Create a special effect at TempPoint[0] using Objects\Spawnmodels\Naga\NagaDeath\NagaDeath.mdl
      • Special Effect - Destroy (Last created special effect)
      • Custom script: call RemoveLocation (udg_TempPoint[0])
      • -------- end --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Poseidon_TWElapsedTime[Spell_Array] Equal to 3.00
        • Then - Actions
          • Unit - Kill Poseidon_TWDummy[Spell_Array]
          • Set Poseidon_TWDummy[Spell_Array] = No unit
        • Else - Actions
So, is it necessary to set TempUnit to No Unit after it's done being used and before I use it again? I read that this won't get recycled so I have to do it myself. Can anyone clear this up for me? I'm under the impression that what i'm doing in these example triggers is the proper method to avoid memory leaks. Thanks.
 

Uncle

Warcraft Moderator
Level 63
Joined
Aug 10, 2018
Messages
6,456
You only need to null local variables. If you don't the handle's reference will never get recycled and the reference counter will increase. After very many leaks this might cause a crash.
Ah okay, so anything in the Variables menu is a Global variable? So I don't need to worry about Nulling tempunit[0] in the triggers above.
 
A unit variable for example is one pointer to a unit object. Each object, so also a unit has a reference (id).

When now the unit gets removed from game, then this reference is functionally not in use anymore. It could be removed/recylced.

But the problem is now, that as long as there is still any pointer (variable) pointing to the unit, then the reference can never be recycled. This is called refence leak, because the reference always exists, even the unit was removed.

So if you declare locals in JASS, you always have to null them, to never risk that problem. You don't want them to point to the unit for ever. Because if a function ends, the locals are gone, and can never be accessed anymore. You can't null, or re-assign them anymore.

In GUI, there are only globals. Technically it's also possible to make a case-scenrio where you have a global variable still pointing on a removed unit. But usually GUI variables are used over and over again, so you don't have to worry that they will always point on a removed unit.

Let's say you create one unit variable "OneSpecialUnitVariable" in GUI, and will use this unit variable only once in a map start trigger, and then this variable will never be used again - then this would cause a reference leak in GUI. Else not.
 
Last edited:

Uncle

Warcraft Moderator
Level 63
Joined
Aug 10, 2018
Messages
6,456
A unit variable for example is one pointer to a unit object. Each object, so also a unit has a reference (id).

When now the unit gets removed from game, then this reference is functionally not in use anymore. It could be removed/recylced.

But the problem is now, that as long as there is still any pointer (variable) pointing to the unit, then the reference can never be recycled. This is called refence leak, because the reference always exists, even the unit was removed.

So if you declare locals in JASS, you always have to null them, to never risk that problem. You don't want them to point to the unit for ever. Because if a function ends, the locals are gone, and can never be accessed anymore. You can't null, or re-assign them anymore.

In GUI, there are only globals. Technically it's also possible to make a case-scenrio where you have a global variable still pointing on a removed unit. But usually GUI variables are used over and over again, so you don't have to worry that they will always point on a removed unit.

Let's say you create one unit variable "OneSpecialUnitVariable" in GUI, and will use this unit variable only once in a map start trigger, and then this variable will never be used again - then this would cause a reference leak in GUI. Else not.

So if I understand correctly then in my Example 3 trigger I SHOULD null the Unit variable "Poseidon_TWDummy[Spell_Array]". The reason being that since it references an indexed dummy unit there's the chance that it may not be used again. Example: I cast a spell 100 times, create 100 dummy units, index all of them, and then once they're all finished and removed I never cast the spell again. Those 100 variables still exist and are still referencing the removed dummy units, thus I need to null them.

However, in the case of using tempunit[0] it's not an issue and I don't need to null it because I will be re-using it very often.

Correct?

EDIT:
Or did I misunderstand you. Are you saying that the only issue is if I try to reference a removed unit?
 
Last edited:
So if I understand correctly then in my Example 3 trigger I SHOULD null the Unit variable "Poseidon_TWDummy[Spell_Array]". The reason being that since it references an indexed dummy unit there's the chance that it may not be used again. Example: I cast a spell 100 times, create 100 dummy units, index all of them, and then once they're all finished and removed I never cast the spell again. Those 100 variables still exist and are still referencing the removed dummy units, thus I need to null them.

However, in the case of using tempunit[0] it's not an issue and I don't need to null it because I will be re-using it very often.

Correct?
Yes. Even though in GUI, the hive standards are not that strict. Most people do not care for reference leaks in GUI, or also many don't maybe know them. But yes, nulling them would prevent the leak, if you for example never user Dummy[50] anymore. And the TempUnit variable gets overwritten always, and so it's not really relevant.

One point why it's not seen so strict in GUI is for sure that many GUI actions internally have reference leaks. So using GUI usually automatically leads to reference leaks. And as a reference leak isn't seen as major leak, it's handled more lenient. If more control of code is wanted on such level then one could always switch to JASS.
 
Last edited:

Uncle

Warcraft Moderator
Level 63
Joined
Aug 10, 2018
Messages
6,456
Yes. Even though in GUI, the hive standards are not that strict. Most people do not care for reference leaks in GUI, or also many don't maybe know them. But yes, nulling them would prevent the leak, if you for example never user Dummy[50] anymore. And the TempUnit variable gets overwritten always, and so it's not really relevant.

One point why it's not seen so strict in GUI is for sure that many GUI actions internally have reference leaks. So using GUI usually automatically leads to reference leaks. And as a reference leak isn't seen as major leak, it's handled more lenient. If more control of conde is wanted on such level then one could always switch to JASS.

Nice, that clears it all up, thanks for the information.
 

Dr Super Good

Spell Reviewer
Level 63
Joined
Jan 18, 2005
Messages
27,178
Nulling is needed to discard references. If the variable will be reused (or index will be reused if it is an array) then there is no need to null.

There is a bug with "local" keyword declared local handle (well agent...) variables that causes a reference counter leak on function return. One must make sure such variables ("local" keyword declared local variables) null such values before they return naturally or as the result of an explicit "return" keyword. This bug may be fixed in future and it plagues the "blizzard.j" functions used by GUI.
 
Status
Not open for further replies.
Top