Verifcation on leaking:

ZakkWylde-

New Member
Reaction score
14
First, I need to make sure that this doesn't leak (and yes I could probably combine the first two functions =P):

JASS:
function yA takes integer Id,real X1,real Y1,real X2,real Y2,real YH returns nothing
	local unit zA=CreateUnit(Player(PLAYER_NEUTRAL_AGGRESSIVE), Id, X1, Y1, YH)
	call IssuePointOrderById(zA,851990,X2,Y2)
    call SetUnitMoveSpeed(zA, 370)
	call GroupAddUnit(udg_Level1Pat,zA) //before you say this leaks...wait
	call GroupAddUnit(udg_AllUnits,zA) //before you say this leaks...wait
	set zA=null
endfunction

function ZA takes integer Id,rect r1,rect r2 returns nothing
    local real X1=GetRectCenterX(r1)
    local real Y1=GetRectCenterY(r1)
    local real X2=GetRectCenterX(r2)
    local real Y2=GetRectCenterY(r2)
	call yA(Id,X1,Y1,X2,Y2,0)
endfunction

function Patrol1 takes nothing returns nothing
    local integer Ar = 'earc'
    
    //===========Archers 
    call ZA(Ar, gg_rct_Level1Archer1a, gg_rct_Level1Archer1b)
    call ZA(Ar, gg_rct_Level1Archer2a, gg_rct_Level1Archer2b)
    call ZA(Ar, gg_rct_Level1Archer3a, gg_rct_Level1Archer3b)
    call ZA(Ar, gg_rct_Level1Archer4a, gg_rct_Level1Archer4b)
    call ZA(Ar, gg_rct_Level1Archer5a, gg_rct_Level1Archer5b)
    call ZA(Ar, gg_rct_Level1Archer6a, gg_rct_Level1Archer6b)
    call ZA(Ar, gg_rct_Level1Archer7a, gg_rct_Level1Archer7b)
    call ZA(Ar, gg_rct_Level1Archer8a, gg_rct_Level1Archer8b)
    call ZA(Ar, gg_rct_Level1Archer9a, gg_rct_Level1Archer9b)
    call ZA(Ar, gg_rct_Level1Archer10a, gg_rct_Level1Archer10b)
    
    call ZA(Ar, gg_rct_Level1Archer11a, gg_rct_Level1Archer11b)
    call ZA(Ar, gg_rct_Level1Archer12a, gg_rct_Level1Archer12b)
    call ZA(Ar, gg_rct_Level1Archer13a, gg_rct_Level1Archer13b)
    call ZA(Ar, gg_rct_Level1Archer14a, gg_rct_Level1Archer14b)
    call ZA(Ar, gg_rct_Level1Archer15a, gg_rct_Level1Archer15b)
    call ZA(Ar, gg_rct_Level1Archer16a, gg_rct_Level1Archer16b)
endfunction
//=======================================================
function InitTrig_Level1Patrol takes nothing returns nothing
    set gg_trg_Level1Patrol = CreateTrigger()
    call TriggerAddAction(gg_trg_Level1Patrol, function Patrol1 )
endfunction


OK; here's the removal of those guys...(eehhh it's a bit GUI converted-looking)

JASS:
function Trig_Level1Finish_Conditions takes nothing returns boolean
    if ( GetUnitTypeId(GetTriggerUnit()) == 'Edem' ) then
        return true
    endif
    return false
endfunction

function Trig_Level1Finish_Func002002 takes nothing returns nothing
    call RemoveUnit( GetEnumUnit() )
    call GroupRemoveUnit(udg_Level1Pat, GetEnumUnit())
    call GroupRemoveUnit(udg_AllUnits, GetEnumUnit())
endfunction

function Trig_Level1Finish_Actions takes nothing returns nothing
    call ForGroupBJ( udg_Level1Pat, function Trig_Level1Finish_Func002002 )
    call DisableTrigger( GetTriggeringTrigger() )
endfunction

//===========================================================================
function InitTrig_Level1Finish takes nothing returns nothing
    set gg_trg_Level1Finish = CreateTrigger(  )
    call TriggerRegisterEnterRectSimple( gg_trg_Level1Finish, gg_rct_Level2Init )
    call TriggerAddCondition( gg_trg_Level1Finish, Condition( function Trig_Level1Finish_Conditions ) )
    call TriggerAddAction( gg_trg_Level1Finish, function Trig_Level1Finish_Actions )
endfunction
 

Xorifelse

I'd love to elaborate about discussions...........
Reaction score
87
It does not leak from what I can see, but it is pretty messy.

Edit:
How do you plan on removing a removed unit from a group?
It is a global.. so even if he doesn't clear the group it still doesn't leak. But yes, the two should be switched around.
 

Azlier

Old World Ghost
Reaction score
461
Is that so?

I think it should be tested.
 

Xorifelse

I'd love to elaborate about discussions...........
Reaction score
87
A group variable type is merely a list of handle ID's which refers to units, at least that is the way something like that should be programmed and it is very unlikely that it isn't.

If so, destroying a group variable just clears the list of handle id's, doesn't matter if they still exist in the game or not.

I tested around with this when I was making my rectdata and rectlist system, should be somewhere around on these forums.

This method however, can make "FirstOfGroup()" and "GetEnumUnit()" return null, so doing loops like:
JASS:
loop
    exitwhen FirstOfGroup(g) == null
    call GroupRemoveUnit( g, u )
    //
endloop

Could end prematurely.
 

Azlier

Old World Ghost
Reaction score
461
I do believe that groups are hashtables, and not removing units from the group leaves shadow references in there. That's why it should slow down so much with so many shadow references...

And if a group is merely a list of ID's, why doesn't the next unit to take the old unit's ID exist in the group? Something special?

Blizzard boggles the mind.
 

Weep

Godspeed to the sound of the pounding
Reaction score
400
even if he doesn't clear the group it still doesn't leak.
Perhaps you should read this. Removing from the game a unit which exists in a unit group causes a leak and a slowdown of unit group operations.
 

Xorifelse

I'd love to elaborate about discussions...........
Reaction score
87
And if a group is merely a list of ID's, why doesn't the next unit to take the old unit's ID exist in the group? Something special?

I'm not sure I understand what you're saying, do you mean when a newly created unit with the same handle id as the removed unit, not replacing the old's units handle ID in the list?

Perhaps you should read this. Removing from the game a unit which exists in a unit group causes a leak and a slowdown of unit group operations.
Perhaps you need a better understanding of the word "Leak".
Yes, group enumerations slow down the more is in the group.
Yes, Memory consumption go's up.
No, It doesn't leak.

It only leaks when you lost reference to a handle, and you are unable to get it back. Destroying or I think even clearing the group, clears the memory of any related data to that group.

Edit => Hinch:
Fortunately, GroupClear solves the problem, and this simple function can be called to remove any built up ghosts in the group
So clearing does the job after all.
 

Azlier

Old World Ghost
Reaction score
461
>not replacing the old's units handle ID in the list?

Exactly.

>Destroying or I think even clearing the group, clears the memory of any related data to that group.

Dynamic groups leak, so destroying really isn't a good idea.
 

Xorifelse

I'd love to elaborate about discussions...........
Reaction score
87
>not replacing the old's units handle ID in the list?

Exactly.

>Destroying or I think even clearing the group, clears the memory of any related data to that group.

Dynamic groups leak, so destroying really isn't a good idea.

A probably theory would be that upon adding such units to the list, it checks if the ID already exists, if so it nulls the index and adds the unit to the end of the list.

  • 1 => #
  • 2 => #
  • null => #
  • 4 => #
 

Azlier

Old World Ghost
Reaction score
461
It's not GroupAddUnit, it's the fact that IsUnitInGroup returns false even if his "successor" was in the group upon removal.
 

Weep

Godspeed to the sound of the pounding
Reaction score
400
Perhaps you need a better understanding of the word "Leak".
[snip]
So clearing does the job after all.
Fair enough. You might notice, though, that in the post of yours that I quoted, you said "even if he doesn't clear the group", which would let the problem build up - is it a leak if it is recoverable, but you don't?
 

Xorifelse

I'd love to elaborate about discussions...........
Reaction score
87
Fair enough. You might notice, though, that in the post of yours that I quoted, you said "even if he doesn't clear the group", which would let the problem build up - is it a leak if it is recoverable, but you don't?
Perhaps the "problem" builds up, but a leak is something that isn't recoverable anymore. Perhaps there are a lot of ghost values inside the group, but that's it. You have reference to each and every unit ever being in that group, which was of course not removed from group.

The fact is, that his unit group is a global variable. Since it is a global variable you will always have reference to it unless you null it ofcourse, and destroy or clear it whenever you want. This should be the way you have to look at this issue. Doesn't matter if ghost values are added to the group, it can be removed since you do have reference.

>It's not GroupAddUnit, it's the fact that IsUnitInGroup returns false even if his "successor" was in the group upon removal.
Then you are correct, Blizzard does boggles the mind. Perhaps all instances of the widgets are nulled in the memory when they get removed. Perhaps not, we could never know for sure. Perhaps our aspects appear easier then they really are. Life has it's uncertainty's, which makes it discussable :)
 

ZakkWylde-

New Member
Reaction score
14
It does not leak from what I can see, but it is pretty messy.

Edit:
How do you plan on removing a removed unit from a group?

It is a global.. so even if he doesn't clear the group it still doesn't leak. But yes, the two should be switched around.

Remove every unit that is in the group after each unit is no longer in the group? Yeah that'll work great :p...
I just thought ghost references to groups were saved, and could be removed even after unit is no longer there (i.e., it has been removed)...

I know ZugZug tried creating lots of units, adding them to groups, and removing them (in a loop fashion)...and it caused severe lag after a while...which is what I'm trying to avoid.

I'm pretty sure this works...and the lag doesn't occur, because I don't lag even after having created hundreds of units...but as far as leaks go, none in this trigger?
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
I tested to remove removed unit from group when making my unit detection. In fact, the removed units will be removed automatically from group, it is not necessary to remove removed units from group. However, there are some ghost reference in group, so you need GroupRefresh function.
 

ZakkWylde-

New Member
Reaction score
14
I tested to remove removed unit from group when making my unit detection. In fact, the removed units will be removed automatically from group, it is not necessary to remove removed units from group. However, there are some ghost reference in group, so you need GroupRefresh function.

To that I respond(ed)

...

I know ZugZug tried creating lots of units, adding them to groups, and removing them (in a loop fashion)...and it caused severe lag after a while...which is what I'm trying to avoid.

...
EDIT/Addition: of course, the lag was not there if he created them, added to group, removed from group, and removed the unit...

---------------------------------------------------------------
...? How did you test that the units were no longer in the group? Can you explain the debilitating lag that comes from creating (lots of) units, adding them to a group, and removing them?

And as I am a half-noob at this point, what does GroupRefresh do...specifically to prevent the lag?
 

ZakkWylde-

New Member
Reaction score
14
GroupRefresh removes all shadows from a unit group.

...the equivalent of removing the unit from the group?!?!??!?!?!@!@#^(*!@&^$!@?? only once the unit has been removed from the game...?
And where do I find this...GroupRefresh...its not (explicitly) in your signature!
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
How did you test that the units were no longer in the group?
Well, test it.
JASS:
scope ProofRemovedUnitsIsRemovedFromGroup

    globals
        group test = CreateGroup()
    endglobals
    
    function AreRemovedUnitsAlsoGetRemovedInGroup takes nothing returns boolean
        local unit u = CreateUnit(Player(0),'hpea',0.,0.,0.)
        call GroupAddUnit(test,u)
        call RemoveUnit(u)
        set u = FirstOfGroup(test)
        return (u == null)
    endfunction
endscope


The first time you test, it will returns false, means the shadow are exist. The next time you test, it will return true, means the removed units will be removed in group automatically.

Originally Posted by Captain Griffen
Units that are removed from the game or decay while part of a group remain in the hash table. They also appear to remain in the list (which can cause issues with FirstOfGroup loops).

Therefore, if units are not removed manually from the group before this happens, there is a minor leak, and the CPU cost of many group operations increases dramatically. Verification is in this thread here.

NB: This only applies to where a group has units in it for longer than an instant, and where those units may decay / be removed. Most uses of groups are not vulnerable to that (most uses you should be using a static group and a boolexpr these days - those are completely unaffected).

Fortunately, GroupClear solves the problem, enabling the creation of a function that can be called on a group and flushes out all of the shadow units in it. The cost is pretty much O(n), where n is the number of real units in the group (rather than shadows).

GroupRefresh does not affect the group in a noticeable way, aside from removing the shadow references in the hash table, which speeds up most operations (see the link above for further details). The only effect it will have on outputs is on FirstOfGroup, which can return null when it comes to a shadow reference in the list, even if there are real units after it. GroupRefresh clears those out, so makes FirstOfGroup act properly again.

More frequent calls of GroupRefresh will reduce CPU costs of most operations involving groups whose usage makes them vulnerable to this, but will incur a higher CPU cost of its own. Look at the benchmarks on the link above and decide for yourself what the best balance is.

So,the GroupRefresh library exists :
JASS:
library GroupRefresh
    
    globals
        private boolean clear
        private group enumed
    endglobals
    
    private function AddEx takes nothing returns nothing
        if clear then
            call GroupClear(enumed)
            set clear = false
        endif
        call GroupAddUnit(enumed, GetEnumUnit())
    endfunction
    
    function GroupRefresh takes group g returns nothing
        set clear = true
        set enumed = g
        call ForGroup(enumed, function AddEx)
        if clear then
             call GroupClear(g)
        endif
    endfunction
    
endlibrary
 

ZakkWylde-

New Member
Reaction score
14
How did you test that the units were no longer in the group?
Well, test it.
JASS:

scope ProofRemovedUnitsIsRemovedFromGroup

    globals
        group test = CreateGroup()
    endglobals
    
    function AreRemovedUnitsAlsoGetRemovedInGroup takes nothing returns boolean
        local unit u = CreateUnit(Player(0),'hpea',0.,0.,0.)
        call GroupAddUnit(test,u)
        call RemoveUnit(u)
        set u = FirstOfGroup(test)
        return (u == null)
    endfunction
endscope


The first time you test, it will returns false, means the shadow are exist. The next time you test, it will return true, means the removed units will be removed in group automatically.

...?!? I'm not sure what this concludes. After a while, the shadows are removed...? Wha'...?
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top