• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Unit leak in loops

Status
Not open for further replies.
Level 3
Joined
Sep 11, 2004
Messages
63
I have seen many code blocks like this without doing "set u = null" inside loop:
Code:
local u
local i

set i = 0
loop
  exitwhen i = 3
  set u = CreateUnit(blah)
endloop
set u = null

Do I need to do "set u = null" inside loop to prevent unit leak?And is a unit leak significant compare to a location/point leak?

Thanks.
 
Level 6
Joined
May 7, 2009
Messages
228
There's no point to nulling u inside the loop. All that matters is whether u is null at the end of the function, and you've already taken care of that.

Also, I could have sworn that CreateUnit does use x,y.
 
Level 3
Joined
Sep 11, 2004
Messages
63
Thanks I guess I will stick with the setting u to null after loop.

And yes CreateUnit takes X,Y while CreateUnitAtLoc takes a location and leaks
 
Level 16
Joined
Mar 3, 2006
Messages
1,564
Also, I could have sworn that CreateUnit does use x,y.

Not all of them; the one you said is:
JASS:
native CreateUnit takes player id, integer unitid, real x, real y, real face returns unit
and
JASS:
native CreateUnitByName takes player whichPlayer, string unitname, real x, real y, real face returns unit
those won't leak a location.

But those two leak a location
JASS:
native CreateUnitAtLoc takes player id, integer unitid, location whichLocation, real face returns unit
and
JASS:
native CreateUnitAtLocByName takes player id, string unitname, location whichLocation, real face returns unit
 
Level 8
Joined
Feb 15, 2009
Messages
463
for you problem just use a unitarray
JASS:
local integer a = -1
local integer e = 5
local unit array u

loop 
  set a = a+1
  exitwhen a>b
  set u[a] = CreateUnit(blaaah)
endloop

set a=-1
loop
  set a = a+1
  exitwhen a>b
  call RemoveUnit(u[a])
  set u[a] = null
endloop
 
Level 3
Joined
Sep 11, 2004
Messages
63
Thanks for the helps, though it seems I have run out of reputation to give out or can't give the same person reputation more than one time =(
 
Level 10
Joined
Aug 19, 2008
Messages
491
for you problem just use a unitarray
JASS:
local integer a = -1
local integer e = 5
local unit array u

loop 
  set a = a+1
  exitwhen a>b
  set u[a] = CreateUnit(blaaah)
endloop

set a=-1
loop
  set a = a+1
  exitwhen a>b
  call RemoveUnit(u[a])
  set u[a] = null
endloop

This is just completely stupid.
When u is assigned a new value the unit's ref-count goes down by 1, thus avoiding the leak.
What you just did is create 5 leaks then use a loop to remove them, instead of just creating 1 leak and removing it with a simple set x = x (like in the first post).
What's up with everyone and their arrays?
 
Level 8
Joined
Feb 15, 2009
Messages
463
This is just completely stupid.
When u is assigned a new value the unit's ref-count goes down by 1, thus avoiding the leak.
What you just did is create 5 leaks then use a loop to remove them, instead of just creating 1 leak and removing it with a simple set x = x (like in the first post).
What's up with everyone and their arrays?

what the hell you are talking????
if e.g. you use a triggered AOE spell without vJASS(so no xe etc) and create dummies for it and the dummies have to be removed this is the only way to prevent their leak() what i did leaked not a byte at all so think of your answers before posting

and the
set x = x
is a leaking thing becoz the previous x isn't removed just overwriten so you are posting complete bulls**t
 
Level 10
Joined
Aug 19, 2008
Messages
491
Huh...
Ok
Let me teach you some basics

Handles are ref-counted, which basically means that every time they are refered to with a variable their ref-count goes up by 1.
When the handle is destroyed, either by some function call or automatically, it will check if its ref-count is 0 or not.
If it is, then everything is well. No leaks.
However, if it isn't 0 (handle-pointers are still refering to it) it will leave a 4 byte 'ghost' in its place consuming the index which we want to avoid.

The ref-count isn't automatically reduced when the local is destroyed at the end of the function, which is why we have to do "set x = null" or assign a new value to the variable; the only way to reduce its ref-count.



So, assinging every fucking dummy to a variable and null it at the end doesn't make it non-leak. In fact, it makes it leak by creating those variables.
What you do here is that you increase the ref-count for every handle by 1, then reduce it by 1 instead of simply leaving it at 0.

Yes, this means that you can have 100 handle-pointer pointing to the same handle, and it will leak just as much as 1 would.
Every local is destroyed at the end of the function, so it's not the local that's leaking; it's the object if its ref-count is not 0.

Hope that made sence to you.
 
Level 8
Joined
Feb 15, 2009
Messages
463
man try it create 5 units always putting a new one to the var and then remove the var u will see that just the last is removed
try this and wonder:
JASS:
local unit u = CreateUnit(p,id,x,y,0.)
call TriggerSleepAction(.00)
set u = CreateUnit(p,id,x,y,0.)
call TriggerSleepAction(.00)
set u = CreateUnit(p,id,x,y,0.)
call TriggerSleepAction(.00)
set u = CreateUnit(p,id,x,y,0.)
call TriggerSleepAction(.00)
set u = CreateUnit(p,id,x,y,0.)

call RemoveUnit(u)
set u = null

just the last created unit will be removed not all
if it would not be like this arrays would be completely useless coz everyone would store everything in just 1 variable so just try it and see


Here the map to check it out for yourself:
 

Attachments

  • aa.w3m
    11.9 KB · Views: 61
Level 10
Joined
Aug 19, 2008
Messages
491
Units are removed by themselves after they decay.
If they don't decay, use a destructor, like you did here.
And will you please listen to me? As long as you kill the unit and null/change any variable refering to it, it will not leak. You don't have to make a f**king 10 sized array for that.

JASS:
function Somefunc takes nothing returns nothing
    local effect e

    loop
        exitwhen something happens
        set e = AddSpecialEffect("some path", x, y )
        call DestroyEffect( e )
    endloop

    set e = null
endfunction

//The above statement will not leak because we constantly destroy
//the handle AND change the variable "e" refering to it
//thus reducing its ref-count.
//The final set e = null makes sure that any handle e is
//refering to have its ref-count go down by 1 before
//e is destroyed.

//What's up with some people and their arrays?

If you're still convinced that creating X amount of arrays, use it once than use a loop to kill them is better than what I just did, I'll stop waste my time with you.

-------- Edit --------
JASS:
//I just thought of an even better way:

function Somefunc takes nothing returns nothing
    loop
        exitwhen something happens
        call DestroyEffect( AddSpecialEffect("some path", x, y ) )
    endloop
endfunction
//This leaks as much as my above one, and is a mayor improvment
//to efficiency
 
Level 21
Joined
Aug 21, 2005
Messages
3,699
thats true but nulling without removing has no sense and never had

and he wanted to know if setting null is preventing the leak and my answer was that only removing(locals + nulling) clears a leak and i gave an example

There are plenty of situations where you do not know when an object will be removed. In those situations, you must still null your variable even if you are not removing it yet. In the case of units: the variables must be nulled, even though the actual unit may only die 5 minutes later by an action of the player.

JASS:
function Test takes nothing returns nothing
    local unit u = CreateUnit()
    set global_u = u
    // We don't remove the unit, so we don't need to null it?
endfunction

function Test2 takes nothing returns nothing
    local unit u = global_u
    call RemoveUnit(u)
    set u = null // This still leaks. We forgot to decrease our reference count of  u in Test.
endfunction
 
Level 8
Joined
Feb 15, 2009
Messages
463
thats true but i never said that this is wrong
what i meant being useless was:
JASS:
local unit u = GetSpellAbilityUnit()
..

..
set u = null



or

local trigger t = CreateTrigger()
Event
Actions
Conditions
set t = null


these things are just useless




// to here
function Somefunc takes nothing returns nothing
    loop
        exitwhen something happens
        call DestroyEffect( AddSpecialEffect("some path", x, y ) )
    endloop
endfunction

creating effects is never a super efficient way coz even destroyed and nulled effects still leak a 0.02 kb(or was it bytes? i think kilobytes)
for the real number i have to look back in gexxo's leaktest thread(i trust him coz he made YouTd CastleFight and so much more that he even can't fail =D)
 
Level 21
Joined
Aug 21, 2005
Messages
3,699
set u = null
why?

set t = null
unless it's a dynamic trigger.

creating effects is never a super efficient way coz even destroyed and nulled effects still leak a 0.02 kb(or was it bytes? i think kilobytes)

0.02 bytes is 0,16 bits. How exactly do you have "fractions of bits"? :D

The original post does not mention removing the units. Hence your solution of using arrays is totally useless. The statement still holds true.
 
Level 8
Joined
Feb 15, 2009
Messages
463
why?


unless it's a dynamic trigger.
we talk about usual things like the mentioned u = GetSpellAbilityUnit() useless nulling



0.02 bytes is 0,16 bits. How exactly do you have "fractions of bits"? :D
Credits to Gexxo for the following thing which i looked up now

:fp:destroyed and nulled effect 66byte it was 0.066kb i had false numbers in mind:mwahaha:

The original post does not mention removing the units. Hence your solution of using arrays is totally useless. The statement still holds true.

he asks if he is preventing the leak and to prevent leaks you have to remove the handles i recognized now your way but the way i showed you will also not leak at all and needs to be done if more units must stay for longer then instant
just to clear things up
i think we both talk in different directions and should stop the discussion now =D
 
Level 3
Joined
Sep 11, 2004
Messages
63
This topic has gone so off, though 66byte is not 0.066KB its 66/1024 or 66 >> 10 in fixed point arithmetic.

set u = null makes sense if warcraft 3 uses smartpointer or reference count memory management, since set variable to null operator effectively reduces reference count in that object by 1, so it will get collected properly when reference count reaches zero. Though if that is true, set u = CreateUnit wont make any sense, since call CreateUnit will work better because it doesn't increase reference count by 1. This should apply to any other variable types too.

I am trying to fix a crash bug in a map, I suspect the crash has something to do with huge leaks over time, but fixing it is so frustrating, cause I have fixed seemingly infinite amount of leak problems I learned from this forum in that map, but the map still crashes in 1 hour or so with "not enough storage to process this command", but the cause of that stupid error remains a mystery. I have checked battle.net forums also, seems people with 8GB memory and 2TB free space still experiencing this problem on certain maps, so it must be a fault of map not PC's. Anothe r possibility I could think of is the map run out of handle id, but I am not even sure if that is possible and whether such problem is big enough to crash the game.
 
Level 10
Joined
Aug 19, 2008
Messages
491
hough if that is true, set u = CreateUnit wont make any sense, since call CreateUnit will work better because it doesn't increase reference count by 1. This should apply to any other variable types too.
Then how are you supposed to refer to that unit later? If you're creating a dummy, you ought to make it do something.
Or a footman, shouldn't it move or something?
Yes, not increasing the referance count is good because you save that extremely large memmory consumption of 4 bytes when it decays, but on the other hand you often need to do more things than just create the unit, don't you?

And no, this isn't going off-topic. Saia_Djinn tried to help you by making 2 loops with effect arrays, where only 1 loop and no variables are needed, and now I'm trying to help you - and him - understand why you should not do what he said.
Maybe you've already understood why, but that was the purpose of starting this discussion.
 
Level 8
Joined
Feb 15, 2009
Messages
463
i undersand about your thing now and agree but my otherstatement if you want to get more dummy units to stay for longer then instant it is the easiest way
@ACDS2 if you just use call CreateUnit you will never be able to catch that unit coz call CreateUnit doesnt save the unit to bj_LastCreatedUnit so set u = CreateUnit is the right thing
to the set u = null

if you set u = GetSpellAbilityUnit() it is useless to null in most cases(e.g. in AOS maps) coz this will mostly be Heros which are never removed except on leave
setting a GetSpellAbilityUnit() variable(u) to null is therefore just a stretching of code
 
Level 3
Joined
Sep 11, 2004
Messages
63
Thanks for the info, I think set u = CreateUnit without setting u = null after is the major leak in a map I am looking at, increasing ref count by 1 without decreasing it later may cause the unit object not get deleted even after the unit is killed/decayed/removed.
 
Status
Not open for further replies.
Top