• 🏆 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!

Things That Leak

Ralle

Owner
Level 77
Joined
Oct 6, 2004
Messages
10,096
For a structured tutorial on the matter, read this.

Hello guys!
Credit to: Wolverabid, PurplePoot, Silvenon, Paskovich

I want to make a list of things that leak and ways to fix them.

Dynamic Unit Groups

This trigger will instantly destroy dynamically generated unit groups.

  • Trigger
    • Events
      • Event
    • Conditions
      • Conditions
    • Actions
      • Custom script: set bj_wantDestroyGroup = true
      • Unit Group - Pick every unit in (Playable Map Area) and do (Unit - Hide (Picked unit))
Another way to avoid a group leak is to store the group into a variable, and then destroy it manually.

  • Set GroupVar = Pick every unit in (Playable Map Area)
  • Unit Group - Pick every unit in GroupVar and do (Unit - Hide (Picked unit))
  • Custom script: call DestroyGroup(udg_GroupVar)
This is useful if you want to use the group more than once in the trigger.​

Dynamic Locations

  • Unit - Create 1 unit at Somewhere
If there is a function, like (Position of (Unit)) or (Center of (Region)), it will leak.

  • Set loc = Somewhere
  • Unit - Create 1 unit at loc
  • Custom script: call RemoveLocation(udg_loc)

Player Groups

Player Groups leak also, but those are really rare. The fix:

  • Player Group
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Some Spell
    • Actions
      • Set PlayerGroup = (All enemies of Player 1 (Red))
      • Player Group - Pick every player in PlayerGroup and do (Do nothing)
      • Custom script: call DestroyForce(udg_PlayerGroup)
Note: (All Players) does not leak, and destroying it may cause problems.

Special Effects

  • Special Effect
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Some Spell
    • Actions
      • Set Point = (Position of (Triggering unit))
      • Special Effect - Create a special effect at Point using Abilities\Spells\Human\ThunderClap\ThunderClapCaster.mdl
      • Special Effect - Destroy (Last created special effect)
      • Custom script: call RemoveLocation(udg_Point)
Note: Creating a special effect and destroying it directly afterwards will still show the effect.

Terrain Deformations

These create a small but permanent leak, so having far too many of them may cause some performance issues.

Spells like Shockwave and Hoof Stomp create terrain deformations, so do not over-use them.​

Things That Always Leak

Never use these functions:

  • Unit Group - Pick all units of type Footman and do...
  • Camera - Pan Camera as needed...
 
Last edited:
Level 10
Joined
Nov 10, 2004
Messages
351
  • Leak
    • Events
    • Conditions
    • Actions
      • Unit - Move (Triggering unit) instantly to ((Position of (Triggering unit)) offset by 100.00 towards 180.00 degrees)
      • -------- Leaks Twice! --------
      • -------- --------
      • Set TempPoint = (Position of (Triggering unit))
      • Unit - Move (Triggering unit) instantly to (TempPoint offset by 100.00 towards 180.00 degrees)
      • Custom script: call RemoveLocation(udg_TempPoint)
      • -------- Still leaks a location --------
      • -------- --------
      • Set TempPoint = (Position of (Triggering unit))
      • Set TempPoint2 = (TempPoint offset by 100.00 towards 180.00 degrees)
      • Unit - Move (Triggering unit) instantly to TempPoint2
      • Custom script: call RemoveLocation(udg_TempPoint)
      • Custom script: call RemoveLocation(udg_TempPoint2)
      • -------- Finnaly no leaks! --------
PolarProjection(Point with polar offset) also creates a location, meaning that it has to be set to a variable and removed.
 
Level 11
Joined
Jul 12, 2005
Messages
764
Another way to avoid a group leak is to store the group instantly to a variable, and then destroy it manually. According to your example, Ralle:
  • Set GroupVar = Pick every unit in (Playable Map Area)
  • Unit Group - Pick every unit in GroupVar and do (Unit - Hide (Picked unit))
  • Custom script: call DestroyGroup(udg_GroupVar)
This is useful is you want to use the group more than one time in the trigger.


EDIT:
In GUI, these two are the most common leaks. Creating any object will of course leak, but it is not that common for example a dummy unit is not killed/removed.
Other leaks should be taken care of mainly in jass, when we create local triggers, timers, and such nasty things.
 
Level 13
Joined
Nov 22, 2006
Messages
1,260
Special effects leak, some people do like this:

  • Speical Effect
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Some Spell
    • Actions
      • Special Effect - Create a special effect at (Position of (Triggering unit)) using Abilities\Spells\Human\ThunderClap\ThunderClapCaster.mdl
(this also covers a common location leak) When it should be like this:

  • Speical Effect
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Some Spell
    • Actions
      • Set Point = (Position of (Triggering unit))
      • Special Effect - Create a special effect at Point using Abilities\Spells\Human\ThunderClap\ThunderClapCaster.mdl
      • Special Effect - Destroy (Last created special effect)
Some people don't realize they had a leak, so it's useful to know.
Also sounds leak, they should be destroyed like this:

  • Sound
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Some Spell
    • Actions
      • Sound - Play (Some Sound)
      • Sound - Destroy (Last played sound)
Player Groups leak also, but those are really rare, I think they are called Forces in JASS, so the fix would be:

  • Player Group
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Some Spell
    • Actions
      • Set PlayerGroup = (All enemies of Player 1 (Red))
      • Player Group - Pick every player in PlayerGroup and do (Do nothing)
      • Custom script: call DestroyForce(udg_PlayerGroup)
Correct me if I'm wrong here
 
Last edited:
Level 11
Joined
Jul 12, 2005
Messages
764
Global timer should not ve destroyed!! When declaring the global variables, a new timer is created for each timer variable.
.
set udg_TimerVar = CreateTimer()
.

If you destroy the timer, you have to create it again, but why would you do that?
So you're wrong with the timer, but right with the special effects. I don't know how forces leak. All i know is (All players) do NOT leak, and if you destroy it, sthg weird (crash or fatal error?) will happen, so that's not the best example, is it? :D
 
Level 13
Joined
Nov 22, 2006
Messages
1,260
Razorbrain, I know it works for you, it should. Leaks are not whether it's working or not, the full name is memory leaks. It's when (example) you create a special effect at the position of a unit. If that location (the position of unit) is not destroyed, it will stay there and take some memory, so when you create lots of these locations, your map will lag like hell. Imagine it like this, try putting 10000 units on a map and test it, it bet it'll lag because each unit takes some memory, and causes the game to leak. Same for Unit Groups, if you go pick every unit, then WE creates a group so he can do what you said, but if that group isn't destroyed, it will leak.

These are what don't leak: integer, real, boolean, string (in JASS code doesn't leak also)

Blizzard should have made a garbage collector for that, though I'm not sure how that works

http://world-editor-tutorials.thehelper.net/cat_usersubmit.php?view=27242
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
These are what don't leak: integer, real, boolean, string (in JASS code doesn't leak also)
Those are what don't leak handles (null leaks). Otherwise, several handles don't leak.

Also, strings technically leak.

A few other things that leak (going into JASS junk) -

-Triggers (duh)

-Triggeractions (have to be removed before destroying the trigger in question)

-Strings, but the reference is only created once. The same string won't leak twice, unlike most leaks.

-Boolexprs generated with And() and/or Or().

-All boolexprs, under the same conditions as Strings. However, boolexprs can be destroyed via DestroyBoolExpr(). If you reuse the boolexpr (as in a trigger that fires more than once, etc), you shouldn't destroy it.

-Weather Effects

-(All Players) is a player group that doesn't leak.

-A whole ton of other things I can't think of right now.

-By the way, the Triggering Unit thing I mentioned wasn't a leak, just an efficiency waste. Triggering Unit can replace any reference to a unit in a trigger where the unit referenced triggered the trigger in question.
Eg. A Unit Casts an Ability -- Triggering Unit = caster
A Unit Is Attacked -- Triggering Unit = unit that was attacked
A Unit Dies -- Triggering Unit = unit that died
 
Level 12
Joined
Aug 18, 2006
Messages
1,193
Razorbrain, I know it works for you, it should. Leaks are not whether it's working or not, the full name is memory leaks. It's when (example) you create a special effect at the position of a unit. If that location (the position of unit) is not destroyed, it will stay there and take some memory, so when you create lots of these locations, your map will lag like hell. Imagine it like this, try putting 10000 units on a map and test it, it bet it'll lag because each unit takes some memory, and causes the game to leak. Same for Unit Groups, if you go pick every unit, then WE creates a group so he can do what you said, but if that group isn't destroyed, it will leak.

These are what don't leak: integer, real, boolean, string (in JASS code doesn't leak also)

Blizzard should have made a garbage collector for that, though I'm not sure how that works

http://world-editor-tutorials.thehelper.net/cat_usersubmit.php?view=27242
oh, ok :p
 
Level 13
Joined
Nov 22, 2006
Messages
1,260
Just a question, does TriggerAddCondition(trig, Condition(function Trig_Blabla_Conditions)) leak? Did you know that you can do that only directly (like that)?? You can't do that with boolexpr local, It took me and HappyTauren about and hour and a half to figure that out.....
 
Level 11
Joined
Jul 12, 2005
Messages
764
It leaks, but it can be cleaned!! I've learned this from Diablo and Purple:
JASS:
local trigger t = CreateTrigger()
local boolexpr be = Condition(function Trig_Blabla_Conditions)
call TriggerAddCondition(t, be)
call DestroyBoolexpr(be)
When destroying the local trigger, triggeractions and conditions should also be removed.
TriggerRemoveAction
TriggerRemoveCondition
JASS:
local trigger t = CreateTrigger()
local boolexpr be = Condition(function Trig_Blabla_Conditions)
local triggercondition tc = TriggerAddCondition(t, be)
local triggeraction ta = TriggerAddAction(t, function Trig_Blabla_Actions)
call DestroyBoolexpr(be)
call TriggerRegister..Event(t, ..)
//At the end when we want to destroy the local trigger:
call TriggerRemoveCondition(t, tc)
call TriggerRemoveAction(t, ta)
call DestroyTrigger(t)
//null all locals!
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
Nope, pask, that's wrong on 2 ends ><

A) if you destroy the boolexpr right away, you're killing the condition

B) you CAN destroy the boolexpr when the trigger is to be discarded, but if there are any other instances of that trigger it can cause problems, as boolexprs are sort of stored like strings. In many cases, it's better to just not destroy them

However, you got TriggerRemoveX right ><
 
Level 21
Joined
Jan 5, 2005
Messages
3,516
here is a question for you, when a place (or point) is written to the memory but is used multiple times does it still leak or not? so say if you wanted to spawn something in the middle of somewhere ever 5 seconds forever, would it lag because although you are writing an address to the memory, you are re-using that address constantly, so there is no point in destroying it when 5 seconds later it is going to be re-written.
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
It's a new point every time. Points aren't stored the same way as strings/boolexprs.

Think units. If you create 2 footmen, are they the same footmen, just because you spawned them both at (Position of (Barracks)) and they have the same stats/type? No, warcraft creates both footmen, not just one.
 
Level 11
Joined
Jul 12, 2005
Messages
764
A few examples on location leaks - and removing them:
Let's say each loop runs 5 times!
This leaks:
JASS:
loop
call CreateSpecialEffectLoc(Location(0,0), "")
call TriggerSleepAction(1)
endloop
->5 leaks

This does not leak:
JASS:
set loc = Location(0,0)
loop
call CreateSpecialEffectLoc(loc, "")
call TriggerSleepAction(1)
endloop
call RemoveLocation(loc)
->0 leaks

But this one does leak again:
JASS:
loop
set loc = Location(0,0)
call CreateSpecialEffectLoc(loc, "")
call TriggerSleepAction(1)
endloop
call RemoveLocation(loc)
->4 leaks (the last one is removed)

While this one does not:
JASS:
loop
set loc = Location(0,0)
 call CreateSpecialEffectLoc(loc, "")
 call RemoveLocation(loc)
 call TriggerSleepAction(1)
 endloop
->0 leaks - but this is inefficent
 
Level 13
Joined
Nov 22, 2006
Messages
1,260
Let's integrate previous posts so Ralle can put it in his first post (leaks are important!):

Strings: They technically leak, there is no way to clean those leaks, but you can avoid it by not having a lot of different strings (don't generate a random string every 0.01 seconds or stuff like that), WE uses the same strings once generated.

Handles: They should be nullified when in a variable, because then a pointer will be left causing a leak. Handles are everything except: integer, real, string, boolean, code
Example:

JASS:
function NullifyHandles takes nothing returns nothing
    local unit c = GetTriggerUnit()
    local location l = GetSpellTargetLoc()
    local timer t = CreateTimer()
    local integer i = GetUnitAbilityLevel(c, 'A000') // don't pay attention to this 'A000'
    // do stuff with those.....
    call RemoveLocation(l)
    call DestroyTimer() // this depends on the situation, maybe this will be done elsewhere
    set c = null
    set l = null
    set t = null
endfunction

Note that integer is not nullified.

Triggers, Trigger Actions, Trigger Conditions: Those leaks should be fixed like this:

JASS:
function DummyCondition takes nothing returns boolean
    return true
endfunction

function DummyAction takes nothing returns nothing
    call KillUnit(GetTriggerUnit())
endfunction

function CleanTriggerLeaks takes nothing returns nothing
    local trigger t = CreateTrigger()
    local triggercondition tc = TriggerAddCondition(t, Condition(function DummyConditions))
    local triggeraction ta = TriggerAddAction(t, function DummyAction)
    //........
    call TriggerRemoveCondition(t, tc)
    call TriggerRemoveAction(t, ta)
    call DestroyTrigger(t)
    set t = null     // note...
    set tc = null   // ...the nullifications...
    set ta = null   // ...here :P
endfunction

Boolexprs: I don't know what exactly boolexprs are, but I've heard they are a string-based type (whatever that means). When using them as a trigger condition, they should not be destroyed (because then the condition is lost too)! But when using them as a group filter (Pick Every Unit In Unit Group Matching) they should be destroyed:

JASS:
function DummyFilter takes nothing returns boolean
    return not IsUnitType(GetFilterUnit(), UNIT_TYPE_DEAD) // this filters only units that are [B]alive[/B]
endfunction

function CleanBoolexprLeak takes nothing returns nothing
    local group g = CreateGroup()
    local boolexpr be = Condition(function DummyFilter)
    local real x = 0
    local real y = 0
    call GroupEnumUnitsInRange(g, x, y, 500, be)
    call DestroyBoolExpr(be)
endfunction

Weather Effects: Should be fixed like this:

JASS:
function CleanWeatherEffectLeak takes nothing returns nothing
    local weathereffect we = AddWeatherEffect('RAhr', bj_mapInitialPlayableArea) // 'RAhr' is id of Ashenvale Rain (Heavy)
    call EnableWeatherEffect(we) // this is necessary for a weather effect to even work! (to show rain)
    // do stuff.....
    call RemoveWeatherEffect(we)
    set we = null
endfunction

Regions/Rects: In JASS there is a region and there is a rect. Don't ask me what's the difference because I don't know. In GUI they are both called regions. Region leaks should be removed like this:

  • Regions
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Some Spell
    • Actions
      • Set Loc1 = (Position of (Triggering unit))
      • Set Region = (Region centered at Loc with size (300.00, 300.00))
      • Set Loc2 = (Center of Region)
      • Unit - Create 1 Footman for Player 1 (Red) at Loc facing Default building facing degrees
      • Custom script: call RemoveLocation(udg_Loc1)
      • Custom script: call RemoveRect(udg_Region)
      • Custom script: call RemoveLocation(udg_Loc2)
Pask had some good examples there, put that also Ralle. Those are common leaks, there are tons of other leaks, but they are so rare that it doesn't even matter. I probably forgot a leak fix or two, so if anyone knows what I've missed, please tell.

I hope it's ok I revived this thread, but I want it to be sticky, can you do that Ralle?
 
Level 1
Joined
May 16, 2007
Messages
4
Hello all, need a little help please.

First of all, just how much will this improve my map, realistically, I mean it's obviously relative but I mean how much would say, going to the trouble of editing a map that's well on the way and destroying 20 or so unit groups, same amount of player groups (not All players though, if i understand correctly, they don't leak?) and setting dynamic locations for about, once again, 20 instances throught the triggers, and such and destroying them too, actually improve performance?

I think I will go ahead and do this regardless, just because I'm a bit of a perfectionist. :wink:

I would also like some clarification as to the custom script for destroying destrutible groups, e.g, I pick all destructibles in a region (created in the editor - do I need to set these regions to a variable too?...) and kill picked destructible. I mean, the unit group one is called DestroyGroup, the player group one is DestroyForce, so what is it for destructibles?

Oh, and an example for it like those on the first post would be great, much easier to see! :grin:

Thanks in advance for any help!

Edit: Also, in ref to this, again from first post:

Set GroupVar = Pick every unit in (Playable Map Area)
Unit Group - Pick every unit in GroupVar and do (Unit - Hide (Picked unit))
Custom script: call DestroyGroup(udg_GroupVar)

This is useful is you want to use the group more than one time in the trigger.


When it says its useful if you want to use it multiple times in one trigger, exactly what does it mean? That you can hold off on the Custom script: call DestroyGroup(udg_GroupVar) until you're done using that group? Or you have to do the whole thing everytime.

And which is more efficient, this or the little one-liner that is something along the lines of 'want to destroy trigger'? (Second seems too easy, must be less efficient? :p)
 
Last edited:
Level 11
Joined
Jul 12, 2005
Messages
764
You won't really notice efficiency change for destroying 20 group/locations/.. leaks. Leaks cause problems mainly in spells, as they are casted more than one time during the game. If it creates let's say 50 location leaks, and is cast 50 times/game, that's 2500 leaks/game. For only one spell!

You don't have to set "generated regions" - that's what they're called - into a variable. They are already set to a generated variable. They look like: gg_rct_RegionName
New regions will be called gg_rct_Region000, gg_rct_Region001, until you change their name. Hope it's clear.
Umm... Destructable groups??

The group-destroying method you wrote is more efficient if you still want to use that group more than one time.
Set GroupVar = Pick ...
Unit group - Pick every unit in GroupVar ...
Do something
Maybe Wait x seconds
Do something else
Unit group - Pick every unit in GroupVar ...
call DestroyGroup(udg_GroupVar)

With bj_wantDestroyGroup, it would create and destroy two groups. - Less efficient.

I hope I cleared everything ;)
 
Level 1
Joined
May 16, 2007
Messages
4
Thanks for all that.

And the destructible groups thing...yes, I realise there is no destructible group type triggers in the game, so perhaps its not a group.

It's just that it involves picking every destructible in a region and doing something to it...it sounds, going by what I've learnt so far, that it might be the sort of thing that leaks, but I guess not? (I'm focusing on the 'pick every unit' thing as my reason for thinking its a leak, but you're right, no mention of it being a 'group' anywhere...so just set me clear here: The above will not leak?).
 
Level 13
Joined
Nov 22, 2006
Messages
1,260
Before picking every unit in whatever you should do set bj_wantDestroyGroup = true, because that gives a signal to the ForGroupBJ function to destroy the group it's "ForGrouping" :p. Don't get the wrong idea, it is a leak.

I have a question related to boolexpr leaks. So boolexprs generated with And() or Or() leak. But what about boolexprs connected with "and" and "or"? Example:

JASS:
function Boolexpr takes nothing returns boolean
    return not IsUnitType(GetFilterUnit(), UNIT_TYPE_DEAD) and IsUnitEnemy(GetFilterUnit(), Player(0))
endfunction

So this doesn't leak?
 
Level 12
Joined
Aug 18, 2006
Messages
1,193
yes, but there is a trigger for removing them
  • Environment - Remove (your weather effect)
i have a problem, this location removal wont work :(
  • Custom script: call RemoveLocation(udg_Region)
theres supposed to be some kind of (rect) problem :/
 
Last edited:
Level 6
Joined
Feb 25, 2005
Messages
230
I cant sort this out still... does this leak:
  • Does this Leak
    • Events
      • Someone answers this
    • Conditions
    • Actions
      • Set Location[4] = (Center of MerchantSpot <gen>)
      • Cinematic - Ping minimap for (All players) at Location[4] for 1.00 seconds, using a Flashy ping of color (30.00%, 100.00%, 100.00%)
      • Unit - Create 1 Elementar Master for Neutral Passive at Location[4] facing Default building facing degrees
      • Custom script: call RemoveLocation( udg_Location[4] )
.
Or do i have to use the custom script removal twice in the trigger, or is it enough to do so only once per trigger?
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
I use UNIT_TYPE_DEAD because GetUnitState()<=0 is not accurate, it may not always work.
Sure it does.

Booleans are connecter with 'and', 'or' and not boolexpr-s.

JASS:
native And              takes boolexpr operandA, boolexpr operandB returns boolexpr
native Or               takes boolexpr operandA, boolexpr operandB returns boolexpr
native Not              takes boolexpr operand returns boolexpr
 
Level 10
Joined
Nov 10, 2004
Messages
351
A little update to this..

I've done some researching about sounds in GUI..And you should NOT destroy them.

When you play a sound in GUI, you just start the sound.

Destroying it would result in that you would not be able to play the sound again, as you are just removing a global sound.

Sounds does only have to be destroyed when you create it as a local:
JASS:
    local sound s=CreateSound(blablabla)
 
Level 6
Joined
Feb 25, 2005
Messages
230
I cant sort this out still... does these locations leak:
  • Does locations Leak
    • Events
      • Someone answers this
    • Conditions
    • Actions
      • Set Location[4] = (Center of MerchantSpot <gen>)
      • Cinematic - Ping minimap for (All players) at Location[4] for 1.00 seconds, using a Flashy ping of color (30.00%, 100.00%, 100.00%)
      • Unit - Create 1 Elementar Master for Neutral Passive at Location[4] facing Default building facing degrees
      • Custom script: call RemoveLocation( udg_Location[4] )
.
Or do i have to use the custom script removal twice in the trigger?

Havent got an answer on this yet...

Heres a new question aswell. Using those two triggers you will find that the second one will not work.

  • Text1
    • Events
      • Time - Elapsed game time is 5.00 seconds
    • Conditions
    • Actions
      • Set tempGroup = (All players)
      • Game - Display to tempGroup the text: Hello!
      • Custom script: call DestroyForce(udg_tempGroup)
  • Text2
    • Events
      • Time - Elapsed game time is 10.00 seconds
    • Conditions
    • Actions
      • Set tempGroup = (All players)
      • Game - Display to tempGroup the text: Hello again!
      • Custom script: call DestroyForce(udg_tempGroup)
So. Does the custom script really destroy the playergroup variable itself, meaning i cant use it no more?

What even wierder is that after using the first trigger (Text1), i cant use this one:

  • Events
    • Time - Elapsed game time is 10.00 seconds
    • Conditions
    • Actions
      • Game - Display to (All players) the text: Hello again!
So. Does the custom script even remove the WE variable (All players) ???
 
Level 10
Joined
Nov 10, 2004
Messages
351
Destroying the force doesn't destroy the variable, only the force it pointed out to.

(All Players) Returns a global force, meaning it should NOT be destroyed.
By destroying (All Players) you will not be able to use it again.. that's why the text isn't being shown again.

Hmmm... I think destroying a unit group renders it unusable, as my spell that uses a unit group only worked once.
When the group is destroyed it's gone(not the variable). But it is only neccesery to destroy it if you have to set the variable to a new group more than once.
 
Last edited:
Top