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

Level 18
Joined
Jan 21, 2006
Messages
2,552
Clearing a hash-table doesn't remove handles from the game. If you've got objects (such as a location, or a rect) in your code then you will need to ensure that it is removed/destroyed appropriately as in any situation.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,454
1. RAM on your computer
2. WarCraft 3 uses RAM
3. War3 uses more RAM during some moments (battles) and less RAM during others (idle moments)
4. So we've established that War3's RAM goes up and down.
5. In the case of a memory-leak, the RAM does not know that it should no longer be there, so the RAM does not go down.

How to fix:

Depending on how far you want to get involved with it, you can A) learn JASS so you can find out every memory leak (because you can see major leaks before your very eyes) or B) study up on some GUI memory leak tutorials.

Either way you slice it, the only way to fix memory leaks in this game is to use JASS.

call DestroyGroup(udg_Group)
  • Custom script: call DestroyGroup(udg_Group)
 
Level 16
Joined
May 1, 2008
Messages
1,605
so...

do "set Caster = Casting unit"
Create - 1 Unit at (Position of 'Caster') facing random angle

will it leak?...

Moin moin =)

You have to do it a little bit different, you need a -point variable-

  • Set TempPoint = Position of (Triggering Unit)
  • Unit - Create 1 Unit at (TempPoint) facing random angle
  • Custom script: call RemoveLocation(udg_TempPoint)
1) As long you don't clear the used variable it will leak.
2) Use (Triggering unit) instead of (Casting Unit)

Greetings
~ The Bomb King > Dr. Boom
 
Level 16
Joined
May 1, 2008
Messages
1,605
Moin moin =)

Nah actually I don't understand it and before I started at hive I used "Casting unit" as well, but then more users here with good experience said "Use Triggering Unit" because the Triggering Unit is the unit which startse the event and casting unit .... ahh I don't know ^^

Greetings
~ The Bomb King > Dr. Boom
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,454
The reason is, behind the inner functionality of game compilation, Casting Unit is likely a function wrapper for Triggering Unit. GetSpellAbilityUnit() is the JASS interface, but it is benchmarked slower than GetTriggerUnit().

Not only, but when you're in GUI, having to not click around as much makes a world of difference (as Triggering Unit is usually your first choice).

While I'm at that "not clicking around as much" thing, you'd be surprised how frequently you can use Triggering Player. Get this: every single trigger that fires from a "Generic Unit Event", Triggering Player will correctly return the owner of the triggering unit. So use Triggering Player if you want to click around not as much (and it's much faster than Get Owning Player).
 
Level 9
Joined
May 30, 2008
Messages
430
I still don't get what the big problem with leaking is. How long must a game be for leaks to cause any kind of lag? 3 hours?

This of course depends on the amount of triggers that leak, but I really don't see the problem.

a single sliding trigger running non stop for 12 players will make the game unplayable in 3-8 minutes just from the locations stored :ugly:
 
Level 16
Joined
Aug 20, 2009
Messages
1,552
try playing something like tank wars(the old versions),

after you finish your game, when you pressed ok at the Score Screen

your computer freezes for (Total Game Time(Minutes) / 2) Minutes

1 game can last for an hour or more...

thats what happend to Dota type of map which spawns creep without removing its leak at the spawning location :D
 
Level 11
Joined
Sep 12, 2008
Messages
657
no idea if any 1 noticed, but at speical effects
he setted point as position of unit
he made the speical effect, destroyed it, but didnt remove the leak..
no idea if the "destroy - speical effect" removes leaks..
 
Level 8
Joined
Oct 26, 2008
Messages
387
  • Custom script: call RemoveLocation (udg_Temp_Point)
yeah ok that works... but not on point variables with arrays... what about them.. when i create a point (array) variable and i try to destroy it with that custom script it doesnt work.. what about that :p?
 
Level 10
Joined
Jan 24, 2009
Messages
606
  • Custom script: call RemoveLocation (udg_Temp_Point)
yeah ok that works... but not on point variables with arrays... what about them.. when i create a point (array) variable and i try to destroy it with that custom script it doesnt work.. what about that :p?

To use array you write [#] after the variable name... then ) behind that again so it should look like:
  • Custom script: call RemoveLocation (udg_Temp_Point[4])
 
Level 2
Joined
Aug 4, 2010
Messages
23
If i use lifespan on floating text then text will dissapear, after that text is destroyed or i must manually destroy it?
  • Set temp_point = (Position of (Picked unit))
  • Floating Text - Create floating text that reads (knockback: + (String(Knockback_integer[4]))) at temp_point with Z offset 0.00, using font size 10.00, color (100.00%, 0.00%, 0.00%), and 0.00% transparency
  • Floating Text - Set the velocity of (Last created floating text) to 64.00 towards 90.00 degrees
  • Floating Text - Change (Last created floating text): Disable permanence
  • Floating Text - Change the lifespan of (Last created floating text) to 1.00 seconds
  • Custom script: call RemoveLocation( udg_temp_point )
 
Level 16
Joined
Aug 20, 2009
Messages
1,552
http://world-editor-tutorials.thehelper.net/cat_usersubmit.php?view=27242

i seen this above tutorial, sound does not leak. -___-" i don't know if that's true but... destroying sound variable made the sound variable unuseable...forever until the map restarts.

Things that leaks according to the above websites are..

Points,
Groups
Region
Special Effects
And Strings.

doesn't show sound though.

does anyone know if sound really does not leak?...now i am curious.

according to me, sound variable only uses the same variable,over and over,the variable only holds that Sound object specifically (set from the Sound editor, i can see the button (use as "Sound Variable")) and never changing, so it would never leak, lets see if my theories hold true.
 
Level 12
Joined
Jul 11, 2010
Messages
422
Indeed, sounds do not leak. When you create a sound (via sound editor), you use the same for all the game and "Play a sound" doesn't create a new sound so you don't need to destroy it.

Items leak too. Mainly the powerups.
When you use a powerup (like a rune), it is not destroyed and, more than leak, it can cause lag because the model is still displayed (it shows a bright point, the last frame of the death animation actually). If you attack any item to death, it won't be destroyed either. They are destroyed if you sell them though.

Also, floating texts are special. There can not be more than 100 text tags at the same time in a map. So what ever you do, you will never leak more than 100 text tag but if you reach this limit, you won't be able to create a new text tag either.
If I remember well, the 100th text tag you create has an handle id of 0, so it is safer to use only 99 of them (for hashtables, for example).
 
Level 12
Joined
Jul 11, 2010
Messages
422
You can use a library that me and Troll-Brain did :
Link to TypeConverter
JASS:
library ClearItems initializer init requires TypeConverter

globals
    private hashtable ItemHash

    // Time for the item's death animation, optimized for tomes and runes.
    private constant real DEATH_TIME = 1.5
endglobals

private function DeleteItem takes nothing returns nothing
    local timer tim = GetExpiredTimer()
    call SetWidgetLife(LoadItemHandle(ItemHash,GetHandleId(tim),0),1)
    call RemoveItem(LoadItemHandle(ItemHash,GetHandleId(tim),0))
    call DestroyTimer(tim)
    set tim = null
endfunction

private function Clean takes nothing returns boolean
    local timer tim = CreateTimer()
    call SaveItemHandle(ItemHash,GetHandleId(tim),0,WidgetToItem(GetTriggerWidget()))
    call TimerStart(tim,DEATH_TIME,false,function DeleteItem)
    call DestroyTrigger(GetTriggeringTrigger())
    set tim=null
    return false
endfunction

function CreateItem2 takes integer itemId,real x,real y returns item
    local trigger trig
    local item it=CreateItem(itemId,x,y)

    if it != null then // If the item isn't created, it's not necessary to create a trigger
        set trig=CreateTrigger()
// Triggers when a powerup is picked and when any item is attacked to death. Does not trigger when an item is pawned.
        call TriggerRegisterDeathEvent(trig,it)
        call TriggerAddCondition(trig,Condition(function Clean))
        call SaveTriggerHandle(ItemHash,GetHandleId(it),0,trig)
        set trig = null
    endif
    return it
endfunction

private function RegisterItemOnBuy takes nothing returns boolean
    local trigger trig = CreateTrigger()
    call TriggerRegisterDeathEvent(trig,GetSoldItem())
    call TriggerAddCondition(trig,Condition(function Clean))
    call SaveTriggerHandle(ItemHash,GetHandleId(GetSoldItem()),0,trig)
    set trig = null
    return false
endfunction

private function CleanCleaningTrigger takes nothing returns boolean
    local trigger trig = LoadTriggerHandle(ItemHash,GetHandleId(GetManipulatedItem()),0)
    if trig != null then
        call DestroyTrigger(trig)
        set trig=null
    endif
    return false
endfunction

private function init takes nothing returns nothing
    local trigger trig = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(trig,EVENT_PLAYER_UNIT_SELL_ITEM)
    call TriggerAddCondition(trig,Condition(function RegisterItemOnBuy))
    set trig = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(trig,EVENT_PLAYER_UNIT_PAWN_ITEM)
    call TriggerAddCondition(trig,Condition(function CleanCleaningTrigger))
    set ItemHash = InitHashtable()
endfunction

endlibrary
The problem with it is that you have to use CreateItem2 instead of CreateItem. We didn't find out a way to use a proper hook for it. So it won't clear leak from item put directly on the map (or droped by monsters).

You can also use a much more simplier librairy that will only fix the powerups leak.
 
Last edited:
Level 18
Joined
Jan 21, 2006
Messages
2,552
JASS:
native EnumItemsInRect takes rect r, boolexpr filter, code actionFunc returns nothing

That will allow you to reference pre-placed items and "register" them to your system.

Not to mention I really wouldn't recommend using that library. You destroy timers and triggers, both of which can cause problems. It also leaks in a number of places:

JASS:
private function Clean takes nothing returns boolean
    local timer tim = CreateTimer()
    call SaveItemHandle(ItemHash,GetHandleId(tim),0,WidgetToItem(GetTriggerWidget()))
    call TimerStart(tim,DEATH_TIME,false,function DeleteItem)
    call DestroyTrigger(GetTriggeringTrigger())
    // set tim = null --> You're not allowing any of these timer handle IDs to be recycled.
    return false
endfunction

JASS:
function CreateItem2 takes integer itemId,real x,real y returns item
    local trigger trig
    local item it=CreateItem(itemId,x,y)

    if it != null then // If the item isn't created, it's not necessary to create a trigger
        set trig=CreateTrigger()
// Triggers when a powerup is picked and when any item is attacked to death. Does not trigger when an item is pawned.
        call TriggerRegisterDeathEvent(trig,it)
        call TriggerAddCondition(trig,Condition(function Clean))
        call SaveTriggerHandle(ItemHash,GetHandleId(it),0,trig)
        set trig = null
        // set it = null -->You're not allowing these created items to recycle properly either.
    endif
    return it
endfunction
 
Level 12
Joined
Jul 11, 2010
Messages
422
Indeed, I forgot that we could use EnumItem :slp:.
And I also leaked that timer you said. But since I return the item, I don't want to null it.
For my defence, we made this script like 3 days ago, it's normal that it can be improved ^^.

Also, I heard a lot that destroying triggers cause problems since I am on THW but I create/destroy triggers since a long time and I never had any crash cause of it. If I recall well, it's the destruction of null triggers that can cause problems and it cannot happen here.

EDIT for razor21 : Wow, I didn't see the main page told that. But it's definitely a mystake. Leak happens when an handle is created and you can't refer to it.
But since it is the same sound which is used during all the game, you can still refer to it.
For the items, you mean using no model for your item? It won't fix the leak but it would fix the lag. Anyway, what's the point to use an invisible item?
 
Last edited:
Level 16
Joined
Aug 20, 2009
Messages
1,552
lol, invisible items?whats the point?..its one of the blessing made by blizzard, that most of us didn't notice...i will tell you,

you could use it for some abilities,
such as enabling attack types, some movement or any upgrades, etc etc,
one example is Psi blade, from Dota Allstars, where when the unit learns that ability, give a glyph of fortification, with an upgrade of "psiblade" which enables attack line.

either, you could use it to increase some status.or maybe use a Rune ability to create illusions, rather that giving a dummy some weird "Item Illusion", and ordering it to use the item at the targeted unit.

it also can come in abilities, such as dispell and stuff, or berserk, even vampiric potion effects, you didn't need to use Disabled spellbooks anymore for giving lifesteal attack for a few seconds and remove it.

etc. all this time, i use "invisible model" for all those in my map.its pretty usefull.

do you get it?.

anyways, you didn't see the main page telling you to destroy sounds?
i will quote it for ya.

Sounds
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)
 
Level 12
Joined
Jul 11, 2010
Messages
422
Yes, I took a look to the main page when you said it but I didn't notice before.

And for items, we speak about general leaking. Of course you can use powerups as a dummy upgrade (even if it is not used in DotA, at least for Psi Blade). But what about items you have to see? It's not a good solution since it won't fix the lag created by the other items.

And now I made more tests, and you just can't fix the leak created by items. You can't remove item when they are dead : it only fixes the lag by hiding the model but the handle isn't destroyed.

Map Example : If you kill (or pickup) the item before removing it, you still will be able to display his name even after trying to remove it.

So, both of the librairies I told don't fix the leak (Vexorian's and mine).

EDIT : I found a way to properly remove a dead item. You have to set its life to > 0.405 before remove it. I edited my code in the previous page to make it. You have to do the same change in Vexorian's code.
 
Last edited:
Level 8
Joined
Jul 14, 2010
Messages
235
If I do this:
  • Custom script: call RemoveLocation(udg_Point)
Is the Location destroyed forever, or can it be used over and over?
I have units that gets created somewhere, and then is ordered to attack-move to Point. This action repeats itself over and over.
 
Level 37
Joined
Mar 6, 2006
Messages
9,240
If I do this:
  • Custom script: call RemoveLocation(udg_Point)
Is the Location destroyed forever, or can it be used over and over?
I have units that gets created somewhere, and then is ordered to attack-move to Point. This action repeats itself over and over.

You can set the point once and then use it over and over again without removing it. Only remove it when you don't need it ever again.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,454
Computers these days have 2-4GB of RAM.

When you open wc3, it consumes 128-256GB of RAM straight away.

When you create a unit, wc3 consumes a bit more RAM because there are more things happening in the game. When you create a thousand units, you notice lag, and your RAM is close to 300-400GB at that point most likely.

When the RAM increases, that is normal when you create new things in wc3. It's a problem if you keep creating new units and never kill/explode/remove them because that means the RAM keeps building and building. If you never destroy something, that is a permanent leak in memory until you restart wc3 and it resets back to 128 or something. Professional maps might consider destroying all handles on the map before the game ends so that users don't have to quit wc3 every few games to handle the leaks.
 

Dr Super Good

Spell Reviewer
Level 63
Joined
Jan 18, 2005
Messages
27,177
Bribe, WHAT THE HELL????
When you open wc3, it consumes 128-256GB of RAM straight away.
When you create a unit, wc3 consumes a bit more RAM because there are more things happening in the game. When you create a thousand units, you notice lag, and your RAM is close to 300-400GB at that point most likely.

Warcraft 3 does not consume 256 GB or 400 GB of RAM. It consumes less than 1 GB of RAM.... It is a 32 bit application so can not consume more than 4 GB.... Starcraft 2 only uses 1-2 GB...

A leak is when data that is no longer needed is stored in memory like it is needed and as such hogs up memory for no reason. The result is memory becomes harder to find meaning memory may need to be paged in and out more often which results in more page faults. Additionally, leaked data may still be registered inside the program like it is in use and as such take up time when performing certain opperations like creating new objects or manipulating old ones.
 
Top