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

this thing leaks a lot

Status
Not open for further replies.
Level 6
Joined
Jul 21, 2011
Messages
139
ive seen this done in spells very often i also asked people if this leaks and they said no, but oh well it turns out it DOES LEAK like crazy according to the handlecounter

  • Destructible - Pick every destructible within 200.00 of Target_Point and do (Destructible - Kill (Picked destructible))
the more trees it destroys the more it leaks, even if they are "dead"

i also use this thing in 0.05 periodic events, to destroy all the trees around the dummy leading the spell

so yeah, help me guys:ogre_rage:
 
Level 6
Joined
Jul 21, 2011
Messages
139
no need for the whole trigger, dont worry im sure this thing leaks

like i said testing with a new map and the handlecounter

interesing thing is that when you command to destroy all the trees in a region, it does not leak (handlecounter number doesnt go up)

so i guess ill have to make a region for every spell with periodic event and move it along the dummy leading the spell

the only problems that i can think of right now is how to do this with spells that are used by more than 1 unit, the region would move like crazy and not function properly
 
When something is dead it isn't necessarily removed from memory (or the game, for that matter). For example, once a unit dies, it'll still leave a corpse for a certain period of time. I am guessing that the same thing is happening, except that it is adding the destructable's "dead" form (assuming your killing trees).

After a short period of time (to let the death animation go through), you should enumerate them as you did above, but instead remove the destructable from the game.
 
Level 6
Joined
Jul 21, 2011
Messages
139
When something is dead it isn't necessarily removed from memory (or the game, for that matter). For example, once a unit dies, it'll still leave a corpse for a certain period of time. I am guessing that the same thing is happening, except that it is adding the destructable's "dead" form (assuming your killing trees).

After a short period of time (to let the death animation go through), you should enumerate them as you did above, but instead remove the destructable from the game.

but the point of the thread is that the "within 200 of" leaks, wich is the oppositive of what a lot of people say and now i have to edit my spells

It should only leak if you are not using a custom script to remove the "target_point".
I can imagine it "lagging" on a low-perfomance PC, if the destructible count is fairly high.
of course im removing the location

it sounds like ur missing something that is the actual cause of the leak. The only thing that the circle one does is it creates a rect and destroys it but doesnt null it. That is the only difference.
i separated and checked the triggers to make sure what was causing the increment in the handlecounter

are you saying that the "within 200 of" creates a rect and destroys it? how are you sure that it gets destroyed? the handlecounter number keeps going up

like i said within 200 of leaks but when you use and move a region it doesnt, i have to go afk now for 10 mins and then i will do more testing
 
Level 30
Joined
Nov 29, 2012
Messages
6,637
I would suggest as what PurgeandFire said, you should remove the destructible when it dies through this trigger:

  • Destructible - Remove (Dying destructible)
Why? Removing a destructible doesnt count as a dead unit anymore for it is removed in the game itself. Now when you picked units, they will not be included on the Pick action.

ANd do you mean by also the dead destructibles, they are included in the Killed destructible? If yes, thats your solution!
 
Level 29
Joined
Oct 24, 2012
Messages
6,543
i separated and checked the triggers to make sure what was causing the increment in the handlecounter

are you saying that the "within 200 of" creates a rect and destroys it? how are you sure that it gets destroyed? the handlecounter number keeps going up

like i said within 200 of leaks but when you use and move a region it doesnt, i have to go afk now for 10 mins and then i will do more testing

no within a radius has nothing to do with what i said. im sure it gets destroyed because i looked at the Jass script that action produces.
the action ur using creates a rect then destroys it. So the only thing that doesnt happen is the rect doesnt get nulled.
The only other thing is as stated previously that u r killing the destructibles. u should remove them instead

Again u should really show ur code.
 
Level 6
Joined
Jul 21, 2011
Messages
139
spell:

  • clen 1
    • Acontecimientos
      • Unidad - A unit Inicia el efecto de una habilidad
    • Condiciones
      • (Ability being cast) Igual a clen
    • Acciones
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • Si: Condiciones
          • KH_IndexSize Igual a 0
        • Entonces: Acciones
          • Detonador - Turn on clen 2 <gen>
        • Otros: Acciones
      • Set KH_IndexSize = (KH_IndexSize + 1)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • Si: Condiciones
          • KH_IndexSize Mayor que KH_M_S
        • Entonces: Acciones
          • Set KH_I[KH_IndexSize] = KH_IndexSize
          • Set KH_M_S = KH_IndexSize
        • Otros: Acciones
      • Set TempInt = KH_I[KH_IndexSize]
      • Set Caster[TempInt] = (Triggering unit)
      • Set Start_Point = (Position of Caster[TempInt])
      • Set Target_Point = (Target point of ability being cast)
      • Set Angle[TempInt] = (Angle from Start_Point to Target_Point)
      • Set Missle_Point = (Start_Point offset by 100.00 towards Angle[TempInt] degrees)
      • Unidad - Activar pausa Caster[TempInt]
      • Animación - Play Caster[TempInt]'s Spell throw animation
      • Unidad - Make Caster[TempInt] face Target_Point over 0.00 seconds
      • Unidad - Create 1 DummyMissle for (Owner of Caster[TempInt]) at Missle_Point facing Target_Point
      • Unidad - Add a 0.80 second Genérico expiration timer to (Last created unit)
      • Unidad - Create 1 DummyMissle for (Owner of Caster[TempInt]) at Missle_Point facing Target_Point
      • Set DummyB[TempInt] = (Last created unit)
      • Set Duration[TempInt] = 1.10
      • Custom script: call RemoveLocation(udg_Start_Point)
      • Custom script: call RemoveLocation(udg_Target_Point)
      • Custom script: call RemoveLocation(udg_Missle_Point)
  • clen 2
    • Acontecimientos
      • Tiempo - Every 0.06 seconds of game time
    • Condiciones
    • Acciones
      • For each (Integer KH_Loop) from 1 to KH_IndexSize, do (Actions)
        • Bucle: Acciones
          • Set TempInt = KH_I[KH_Loop]
          • Set Duration[TempInt] = (Duration[TempInt] - 0.05)
          • Set Missle_Point = (Position of DummyB[TempInt])
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • Si: Condiciones
              • Duration[TempInt] Menor que o igual a 0.00
            • Entonces: Acciones
              • Unidad - Desactivar pausa Caster[TempInt]
              • Unidad - Remove DummyB[TempInt] from the game
              • Unidad - Create 1 DummyExplosion3 for (Owner of Caster[TempInt]) at Missle_Point facing Vista edificio predeterminada degrees
              • Animación - Change (Last created unit)'s animation speed to 50.00% of its original speed
              • Unidad - Add a 2.00 second Genérico expiration timer to (Last created unit)
              • Set DummyB[TempInt] = Ninguna unidad
              • Set Caster[TempInt] = Ninguna unidad
              • Set KH_I[KH_Loop] = KH_I[KH_IndexSize]
              • Set KH_I[KH_IndexSize] = TempInt
              • Set KH_IndexSize = (KH_IndexSize - 1)
              • Set KH_Loop = (KH_Loop - 1)
              • Custom script: call RemoveLocation(udg_Missle_Point)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • Si: Condiciones
                  • KH_IndexSize Igual a 0
                • Entonces: Acciones
                  • Detonador - Turn off (This trigger)
                • Otros: Acciones
            • Otros: Acciones
              • Set Target_Point = (Missle_Point offset by 65.00 towards Angle[TempInt] degrees)
              • Unidad - Move DummyB[TempInt] instantly to Target_Point
              • Unidad - Create 1 DummyCore1 for (Owner of Caster[TempInt]) at Target_Point facing Vista edificio predeterminada degrees
              • Unidad - Add a 1.00 second Genérico expiration timer to (Last created unit)
              • Set grupote[1] = (Units within 200.00 of Target_Point matching (((Matching unit) belongs to an enemy of (Owner of Caster[TempInt])) Igual a True))
              • Grupo de unidad - Pick every unit in grupote[1] and do (Actions)
                • Bucle: Acciones
                  • Unidad - Cause Caster[TempInt] to damage (Picked unit), dealing ((Real((Inteligencia of Caster[TempInt] (Excluir bonuses)))) x 2.00) damage of attack type Caos and damage type Magia
              • Custom script: call DestroyGroup(udg_grupote[1])
              • Destructible - Pick every destructible within 200.00 of Target_Point and do (Destructible - Kill (Picked destructible))
              • Custom script: call RemoveLocation(udg_Target_Point)
              • Custom script: call RemoveLocation(udg_Missle_Point)
info about the testing in next post
 
Level 25
Joined
Sep 26, 2009
Messages
2,378
Try it with other destructibles. I think the cause may be that trees, pathing blockers, etc have 2 versions - <name> and "<name> (Dead)"
The problem may be that it does kill those destructibles, but in their place it creates their (Dead) version, hence why handlecounter goes up.
 
Level 6
Joined
Jul 21, 2011
Messages
139
for the test i removed 2 eye candy units so the numbers i would get were more accurate

edit: i also removed the "spam dummy trigger" for the same reason i mentioned above
  • Unidad - Create 1 DummyCore1 for (Owner of Caster[TempInt]) at Target_Point facing Vista edificio predeterminada degrees
-----------------------------------------

spell without damage and tree destroyer triggers, handlers go up by 3 then go back to normal (supposed to mean that the spell is clean and has no leaks)

spell without damage triggers used at an open place (no trees) , hanlders go up by around 20 (the tree destroyer trigger is leaking here even if it didnt destroy any trees)

spell without damage triggers used to destroy two trees, handlers go up by 36 (the tree trigger is leaking here even more)

spell without damage triggers used to destroy a bunch of trees, handlers go up by 138!!!!

----------------------------

now i use the "new" tree killer method, region (and moving the region) instead of circle

spell without damage triggers used to destroy a bunch of trees , handlers do not go up

---------------------------------------

all this means if you use this kind of tree destroyer

  • Destructible - Pick every destructible within 200.00 of Target_Point and do (Destructible - Kill (Picked destructible))
the number of the handlercounter will increase by a lot and with 12 players in your map spamming spells for 1 hour it adds up

---------------------------------
now i will test the damage trigger i think it makes the handlecounter number go up
  • Set grupote[1] = (Units within 200.00 of Target_Point matching (((Matching unit) belongs to an enemy of (Owner of Caster[TempInt])) Igual a True))
  • Grupo de unidad - Pick every unit in grupote[1] and do (Actions)
    • Bucle: Acciones
      • Unidad - Cause Caster[TempInt] to damage (Picked unit), dealing ((Real((Inteligencia of Caster[TempInt] (Excluir bonuses)))) x 2.00) damage of attack type Caos and damage type Magia
  • Custom script: call DestroyGroup(udg_grupote[1])
maybe because it also uses "within 200 of"
 
Level 6
Joined
Jul 21, 2011
Messages
139
Try it with other destructibles. I think the cause may be that trees, pathing blockers, etc have 2 versions - <name> and "<name> (Dead)"
The problem may be that it does kill those destructibles, but in their place it creates their (Dead) version, hence why handlecounter goes up.
like i said, its about the method,

you use "within of" and the number will increase

you use a region and move it and the number will not increase (discovered this today)

----------------------------------------------------

  • Set grupote[1] = (Units within 200.00 of Target_Point matching (((Matching unit) belongs to an enemy of (Owner of Caster[TempInt])) Igual a True))
this makes the handlecounter numbers go up a bit (even if i use the region method), but i guess theres no solution for this one
 
Last edited:
Have you tested these in a secluded test environment, basicly, an empty map?

Just because the handle counter goes up doesn't mean it's related to this action.

It could be caused by triggers firing when destructables get destroyed or units get damaged, etc.

Also, the action itself doesn't leak handles (it does leak handle IDs, though, which might be the cause for the behaviour of the handlecounter).
Which handlecounter are you using, btw?

Also, a handle counter does not yield perfect results here, as there are lots of dummys involved in your trigger. Unit don't get instantly recycled when killed.
 
like i said, its about the method,

you use "within of" and the number will increase

you use a region and move it and the number will not increase (discovered this today)

----------------------------------------------------

  • Set grupote[1] = (Units within 200.00 of Target_Point matching (((Matching unit) belongs to an enemy of (Owner of Caster[TempInt])) Igual a True))
this makes the handlecounter numbers go up a bit (even if i use the region method), but i guess theres no solution for this one

My mistake. I thought you were just talking about the destructables.

Yes the function does leak. It is not leaking the actual handle's memory, but rather the handle ID is not being recycled. This is because the Blizzard function does not null its variables, as deathismyfriend pointed out. :)

JASS:
function EnumDestructablesInCircleBJFilter takes nothing returns boolean
    local location destLoc = GetDestructableLoc(GetFilterDestructable())
    local boolean result

    set result = DistanceBetweenPoints(destLoc, bj_enumDestructableCenter) <= bj_enumDestructableRadius
    call RemoveLocation(destLoc)
    return result
endfunction

function EnumDestructablesInCircleBJ takes real radius, location loc, code actionFunc returns nothing
    local rect r

    if (radius >= 0) then
        set bj_enumDestructableCenter = loc
        set bj_enumDestructableRadius = radius
        set r = GetRectFromCircleBJ(loc, radius)
        call EnumDestructablesInRect(r, filterEnumDestructablesInCircleBJ, actionFunc)
        call RemoveRect(r)
    endif
endfunction

//=============

The rect is not nulled and neither is the location in the callback (EnumDestructablesInCircleBJFilter) does not null the location. That would explain why the handle count gets increased by X destructables every time it is called. Nothing you can do about that in GUI except use a different function. Otherwise you have to resort to JASS.
 
i didnt know that not nulling it doesnt recycle the handle ids into the id pool. Thanks for that lol.
So its something that looks like a leak but it isnt.

Sort of. :) It still is considered a leak. It just isn't the same as the usual one. Here is a good explanation by phyrex1an:
http://wiki.thehelper.net/wc3/Variables said:
Discarding
The agent types in Jass are reference-counted. This means that whenever a variable is set to point to an agent, this agent's reference counter is increased by one, and when a variable pointing to an agent is set to point to something else, the agent's reference counter is decreased. If an agent's reference count is not 0, its handle id and memory cannot be freed.

The reference counter of an agent should also decrease when a local variable pointing to it disappears (i.e. when the function instance it was created in ends), but due to a mistake by Blizzard, this doesn't happen. As a result of this, most agent types1 need to be nulled2 before the function ends, as not doing so would lead to the agent's reference counter never reaching 0, thus its memory and handle id staying reserved even when the agent itself is destroyed, creating a memory leak. If the value of a local handle variable is returned, it is not and cannot be nulled. To prevent a leak, a global variable should be set to the local variable, the local variable nulled, and the global variable returned instead.
 
Status
Not open for further replies.
Top