- Joined
- Sep 6, 2013
- Messages
- 6,742
Memory leaks
For a quick lookup on most important actions, read Things That Leak.
Introduction
If your computer's memory keeps occupied with stuff you already lost access to, it's called memory leak. It slows down the computer for no benefits.
Having tons of leaks may lead to lag-spikes upto a total game freeze.
This tutorial will explain how to keep your code as leakfree as possible.
Object Leaks
What is an object leak?
An object is something you can create with triggers, like a unit, a unit group, or a floating text.
If an object exists, but you can't use it anymore it's considered an object leak.
All in-game created objects should always be destroyed after they fulfilled their purpose.
Example where objects are created:
It's easy to guess a new unit object is created, but watch out, there's more.
"(Center of (Playable map area))" creates a new point object. As it is, it will leak.
"(Units in (Playable map area))" creates a new unit group object. As it is, it will leak.
So the above lines use objects to operate. Always when objects are involved, there's a risk to leak.
But be aware that not only actions might use objects, but also condtions can use them:
"(Units in (Playable map area))" creates a new unit group object, too! As it is, it will leak, even it's in a condition.
How to prevent object leaks?If an object exists, but you can't use it anymore it's considered an object leak.
All in-game created objects should always be destroyed after they fulfilled their purpose.
Example where objects are created:
|
"(Center of (Playable map area))" creates a new point object. As it is, it will leak.
|
So the above lines use objects to operate. Always when objects are involved, there's a risk to leak.
But be aware that not only actions might use objects, but also condtions can use them:
|
Some examples to destroy objects:
Example
We want to create a special effect, and to prevent a leak we'll call its destroy function after usage:
Though, GUI does not provide all destroy functions we need.
Sometimes we have to use a custom script as help. But don't worry, it's always only one line.
Locations
Unit Groups
For groups you can even use an other method.
If you set "bj_wantDestroyGroup" to "true" via custom script, it will automatically destroy the next unit group creation, that is done via GUI.
Player Groups
Be warned that "(All Players)" doesn't leak, as it's a constant. Never destroy it!
Following doesn't leak, and can be used just like that:
There are some things which are worth an extra note:
Technique of removal
We often use variables that help us to refer to the object being destroyed.
Important is that you don't overwrite the variable with other values before the object is actually destroyed!
Let's go by simple example where we want to destroy two locations:
In the bad example you lost access to Location_1, because the variable was overwritten.
Location_1 can't be removed anymore, so it will leak.
|
|
|
|
|
|
|
|
|
Example
We want to create a special effect, and to prevent a leak we'll call its destroy function after usage:
|
Sometimes we have to use a custom script as help. But don't worry, it's always only one line.
Locations
|
|
If you set "bj_wantDestroyGroup" to "true" via custom script, it will automatically destroy the next unit group creation, that is done via GUI.
|
|
Following doesn't leak, and can be used just like that:
|
Overview
Death Animation
Units
Items
- Destroying something will still play its death animation.
- Units get automatically removed after their corpse decayed.
- Items are never being automatically removed.
If you for example destroy a special effect directly after creation, its death animation will still correctly play:
It's also applayable for items, units and destructibles. Killing/destroying will always play the death animation, while removing won't!
|
It's also applayable for items, units and destructibles. Killing/destroying will always play the death animation, while removing won't!
When a unit dies it still exists in the game, but it's just dead. Usually it lets some corpse behind and can be revived at some later point.
Only after the corpse decayed, it means the unit was fully removed from the game. Then it's the same as you would use:
So it's usually not required to clean up after normal unit deaths, as the game cleans them up on its own.
Only after the corpse decayed, it means the unit was fully removed from the game. Then it's the same as you would use:
|
Items never get properly removed after they died, or were used (Tomes/Powerups).
If you want dead items being automatically cleaned up you can take usage of a system which does it for you:
If you want dead items being automatically cleaned up you can take usage of a system which does it for you:
- For GUI: Item Cleanup 1.3
- For JASS: [System] Item Cleanup
Technique of removal
We often use variables that help us to refer to the object being destroyed.
Important is that you don't overwrite the variable with other values before the object is actually destroyed!
Let's go by simple example where we want to destroy two locations:
Good example: | Bad example: |
|
|
Location_1 can't be removed anymore, so it will leak.
Reference Leaks
<< If you don't use JASS you can skip this chapter. >>
What is a reference leak?
Firstly, only children types by the agent type are affected by the reference leak. Other handles don't suffer from it.
An agent basically contains one address to an object, and one reference counter for it.
- The object itself is what we have access to. It can be a unit, group, timer, or what ever. You have powers to destroy this object on yourself.
- The reference counter is the number of variables pointing on this agent. It increases/decreases automatically when ever you assign variables.
C:
struct Agent
{
Object* object;
int referenceCounter;
};
For us, it's only important to know that next to the object itself, there's a bit more memory in use for the agent.
And there's actually a problem with this memory being automatically deallocated, even if we destroy the used object behind.
To let this memory for the agent automatically deallocate, you have to destroy the object and have to ensure its reference counter is 0, meaning there are no more variables pointing on it.
If the agent can not be deallocated anymore, due to an reference counter above 0, this is what is called reference leak. Its agent's id, the handleid, can never be recycled.
How to prevent reference leaks?
We want to ensure an agent's reference counter is 0, when we're about to destroy its object.
To achieve this we always let our variables point on something else, after they fullfilled their purpose and before they fall out of scope.
Example:
At the top of the function we increase the reference counter for the agent on which
To achieve this we always let our variables point on something else, after they fullfilled their purpose and before they fall out of scope.
null
comes handy here, as you may apply it to any agent
type.Example:
JASS:
function foo takes nothing returns nothing
local group g = CreateGroup()
call DestroyGroup(g)
set g = null
endfunction
g
refers to, but we also ensure it's decreased again at the end of the function. And done! The agent won't have any issue to free its memory after the function has ended, because its reference counter is 0.Technique of removal
When the variable does point to
In the bad example the destroy function will fail, because
null
, it does of course also mean that it doesn't point to the agent anymore. So, if you want to destroy the object, you firstly must ensure to destroy the object before you null
the variable.Good example: | Bad Example: |
JASS:
|
JASS:
|
g
does not point to the group anymore. It would result in an object leak.
Miscellaneous
Leaks And Data Types
If something can leak depends on its data type:
Overview
Primitives
Enums
Objects
- Primitives never leak.
- Enums never leak.
- Objects can leak!
There exist 6 primitive/native data types:
As a GUI user you maybe didn't read something about
integer , boolean , real , string , code , handle
As a GUI user you maybe didn't read something about
code
or handle
so far, but don't worry, it's not really relevant for GUI.You can imagine enums as special form of an integer but with a new name.
JASS:
race
alliancetype
racepreference
gamestate igamestate fgamestate
playerstate
playerscore
playergameresult
unitstate
aidifficulty
eventid
gameevent
playerevent
playerunitevent
unitevent
limitop
widgetevent
dialogevent
unittype
gamespeed
gamedifficulty
gametype
mapflag
mapvisibility
mapsetting
mapdensity
mapcontrol
fogstate
playerslotstate
volumegroup
camerafield
playercolor
placement
startlocprio
raritycontrol
blendmode
texmapflags
effecttype
version
itemtype
attacktype
damagetype
weapontype
soundtype
pathingtype
Objects can be something like
And basically much more! Everything that you can create or destroy is an object!
effect , unit , timer , group , multiboard
.And basically much more! Everything that you can create or destroy is an object!
Things that always leak
There are some leaks that you can't prevent.
- A unit will always keep a tiny bit of memory, even when removed properly. 0.04 kb and unpreventable. (Link)
- Terrain deformations leak. Including default abilities like shockwave. (reference leak)
- Very much BJs (Blizzard JASS functions) which are mostly used in GUI have reference leaks.
You might always look them up to see how a BJ is defined at blizzard.
Leaks and RAM
- Location: 0.361 KB
- Group: 0.62 KB + 0.040 KB for each unit in the group.
- Effect: 11.631 KB
Source: Automatic Memory Leak Destroyer - Wc3C.net
Other Tips
- If the black screen freezes after game-end it may be an indicator for huge amount of leaks. Don't worry if it's a only a few seconds - it might also be the normal memory usage your map needs.
- Lags are not necessarily a proof for leaks. Highly inefficient coding may also result in lags for example.
- An indicator for major leaks might be noticed in task manager. Just watch the memory usage of WC3 while running the map.
If it's increasing very fast and continuously, you might check your triggers again. (code that runs periodicly or is called very often is most important)
- As GUI handles certain object initialization by default, (for arrays index [0] and [1]), it does technically leak once if you create for example a unit group for the first time and so overwrite the initialy created group, without having destroyed it. Example creation:
- Set Group = (Units owned by Player 1(Red))
Conclusion
- Always remove objects after usage, else you will have an object leak.
- Always null agent type variables, else you will have a reference leak.
- Object leak is the major leak, but the reference leak is still a leak so don't neglect it.
Last edited: