HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Memory Leaks and Custom Scripts

02-03-2006, 01:41 PM#1
emjlr3
~~emjlr3's Memory Leak / Custom Script Guide~~

I have seen this going around a lot lately, people asking for help with memory leaks and custom scripts. This tutorial is to provide knowledge of the basic memory leaks and ways to clean them up using custom scripts, for those of us who are not yet intone enough with JASS to make all our triggers using such. This also should provide us with a quick answer to all those posts about this, so we can just send people in the direction of this thread, and tell them to read. Let us begin:

Let me start by introducing everyone to the not so common terms I will be using:

Memory Leak:
the leakage of handle objects, or in other words, basically whenever you create something or reference something, other than integers the game loses it’s location, thus causing a leaked piece of memory. Now granted these are cleaned at the end of the game, but if enough pile up during play without being removed, it can cause serious lag to the players, ranging from a little here and there, to complete un-playability, neither of which is wanted.

Jass:
the scripting language used for scripting Maps and AI files in Blizzard Entertainment's Warcraft III game. Most people make triggers in GUI format, the premade template triggers that are in the World Editor. However, the actual language of these is that of JASS, which can give you almost free reign over every aspect of the game.

Custom Script:
this is an action in the World Editor Trigger Editor which allows you to type something in GUI and have it converted to custom script, a.k.a JASS. This is what we will be using to clean up most of our memory leaks, since Blizzard put in the ability to remove these leaks, but neglected to add them to basic GUI.


Now many different things can cause memory leaks, these include:

Special Effects
Groups
Points
Units
Regions
Forces
Lightning Effects
Floating Text
Countdown Timers
(There may be more which I have forgotten, but these are the ones that need to be dealt with the most, since they are most commonly used.)
Strings - However, these can not be cleaned up, and you will just have to deal with the leaked memory. They are not to big of a deal though since each string only leaks once, so the same string will only leak the first time used. In the end strings are something that don't really need to be worried about, however dont go doing something stupid such as:

Trigger:
Collapse Events
Time - Every 0.01 sec of game time
Conditions
Collapse Actions
set SomeInteger = SomeInteger + 1
Game - Display Text to All Players (String(SomeInteger))

For this will surely cause lag eventually. So just use common sense when using strings.


Now I will show you examples of each of the most common, with memory leaks, and then after cleaning them up:

Unit Groups


Trigger:
Unit Group Bad
Events
Conditions
Collapse Actions
Collapse Unit Group - Pick every unit in (Units in (Playable map area)) and do (Actions)
Collapse Loop - Actions
Unit - Kill (Picked unit)

Now this will leak memory evert time ran, which, depending on how many times this is ran, can add up heavily.

Trigger:
Unit Group Good
Events
Conditions
Collapse Actions
Set Temp_Group = (Units in (Playable map area))
Collapse Unit Group - Pick every unit in Temp_Group and do (Actions)
Collapse Loop - Actions
Unit - Kill (Picked unit)
Custom script: call DestroyGroup (udg_Temp_Group)

This cleans up all of your leaks. We first set our unit group to a unit group variable, pick all the units in this variable, do our actions, and then destroy the unit group variable, using a Custom Script. Remember that when referencing a variable in JASS, you most use underlines for spaces and put ‘udg’ before the Variable name.


Points

Trigger:
Point Bad
Events
Conditions
Collapse Actions
Unit - Create 1 Footman for Player 1 (Red) at (Center of (Playable map area)) facing Default building facing degrees

The unit created at the region leaks. This is not a major leak, but depending on the amount of units created, and how often, it can add up.

Trigger:
Point Good
Events
Conditions
Collapse Actions
Set Temp_Point = (Center of (Playable map area))
Unit - Create 1 Footman for Player 1 (Red) at Temp_Point facing Default building facing degrees
Custom script: call RemoveLocation (udg_Temp_Point)

By setting our position that we want the unit to be created at, creating it at the variable, then removing it, we remove all leaks.


Special Effects

Trigger:
Special Effect Bad
Events
Conditions
Collapse Actions
Special Effect - Create a special effect at (Center of (Playable map area)) using Abilities\Spells\Human\ThunderClap\ThunderClapCaster.mdl

This introduces a new leak, the special effect leak, and has one we just went over, the point leak. We need to remove both of these.

Trigger:
Special Effect Good 1
Events
Conditions
Collapse Actions
Set Temp_Point = (Center of (Playable map area))
Special Effect - Create a special effect at Temp_Point using Abilities\Spells\Human\ThunderClap\ThunderClapCaster.mdl
Special Effect - Destroy (Last created special effect)
Custom script: call RemoveLocation (udg_Temp_Point)

In the same fashion as before, we remove our leaks. Special effects are one of the only things you can remove through GUI functions, and no custom script is needed. Whenever you create a special effect, you should always destroy it, even if it looks as though it destroys itself, such as in this case with Thunder Clap. Now some special effects, if destroyed directly after being made, never show at all. In that case you have to add a wait in, then destroy the special effect at a later time.

Trigger:
Special Effect Good 2
Events
Conditions
Collapse Actions
Collapse For each (Integer A) from 1 to 10, do (Actions)
Collapse Loop - Actions
Set Temp_Point = (Center of (Playable map area))
Special Effect - Create a special effect at Temp_Point using Abilities\Spells\Undead\UnholyAura\UnholyAura.mdl
Set Temp_SFX[(Integer A)] = (Last created special effect)
Custom script: call RemoveLocation (udg_Temp_Point)
Wait 2.00 seconds
Collapse For each (Integer A) from 1 to 10, do (Actions)
Collapse Loop - Actions
Special Effect - Destroy Temp_SFX[(Integer A)]

This is an example if you wanted to have a wait, and create many special effects at once. This stores each into a special effect variable array, and destroys them all at a later time.

Units

The last major leak is that of units( although it is not really a leak, since units themselves create no memory leaks, but not removing them can be a major cause of lag). Many people like to use dummy units to create neat triggered spells and such. If these units are not removed, they can just pile up all around the map, leading to some major lag. We use our example from before:

Trigger:
Units Bad
Events
Conditions
Collapse Actions
Unit - Create 1 Dummy Caster for Player 1 (Red) at (Center of (Playable map area)) facing Default building facing degrees

There is a very easy way to remove them after they are no longer needed. Remember to fix your other point leak too.

Trigger:
Units Good
Events
Conditions
Collapse Actions
Set Temp_Point = (Center of (Playable map area))
Unit - Create 1 Dummy Caster for Player 1 (Red) at Temp_Point facing Default building facing degrees
Custom script: call RemoveLocation (udg_Temp_Point)
Unit - Add a 2.00 second Generic expiration timer to (Last created unit)

This adds an expiration timer to the unit, so it is destroyed after 2 seconds. This is usually enough time for it to do what it needs to, but you can change it for your personal needs.

Other Possibilities

That pretty much covers all the major leaks problems people have in their maps. Here are a few more custom script functions you can use to remove other leaks that sometimes occur:

Trigger:
Custom script: call DestroyForce( udg_Your_Variable ) //Player Group

Trigger:
Custom script: call RemoveRect(udg_Your_Variable) //Region

Trigger:
Custom script: call DestroyLightning( udg_Your_Variable ) //Lightning Effect

Trigger:
Custom script: call DestroyTextTag( udg_Your_Variable ) //Floating Text

This is one of the only things that can also be easily destroyed in GUI. There ar two way of doing this, each are equally effective.

Trigger:
Floating Text - Change the lifespan of (Last created floating text) to 5.00 seconds
Floating Text - Destroy (Last created floating text)

The first simply adds a destroy timer to the text tag, and it will be destroyed in 5 seconds, the second is a manual destroy you can do yourself.


Trigger:
Custom script: call DestroyTimer( udg_Your_Variable ) //Countdown Timer

and lastly, one good Custom Script to use is that when you have a trigger that will only run once, then is useless. In those cases, put this at the end of the trigger. It can greatly reduce lag in your maps.

Trigger:
Custom script: call DestroyTrigger( GetTriggeringTrigger() )


Final Trigger


Let us put all our newly acquired knowledge together for one final leak less trigger.

Trigger:
Final Good Trigger
Collapse Events
Unit - A unit Starts the effect of an ability
Collapse Conditions
(Ability being cast) Equal to Animate Dead
Collapse Actions
Set Temp_Point = (Position of (Casting unit))
Special Effect - Create a special effect at Temp_Point using Abilities\Spells\Human\ThunderClap\ThunderClapCaster.mdl
Special Effect - Destroy (Last created special effect)
Set Temp_Group = (Units within 512.00 of Temp_Point matching (((Matching unit) is A structure) Equal to False))
Custom script: call RemoveLocation (udg_Temp_Point)
Collapse Unit Group - Pick every unit in Temp_Group and do (Actions)
Collapse Loop - Actions
Set Temp_Point = (Position of (Picked unit))
Unit - Create 1 Dummy Caster for (Owner of (Casting unit)) at Temp_Point facing Default building facing degrees
Unit - Order (Last created unit) to Human Priest - Inner Fire (Picked unit)
Unit - Add a 2.00 second Generic expiration timer to (Last created unit)
Custom script: call RemoveLocation (udg_Temp_Point)
Custom script: call DestroyGroup (udg_Temp_Group)

You have completed my tutorial. I hope you have learned a thing or two, and happy mapping!!

Feel free to visit http://jass.sourceforge.net/index.shtml for a list of all JASS functions known, some JASS tools, and a very good JASS manual.

v 1.05

Possibly More To Come...
02-04-2006, 03:34 PM#2
shadow1500
found some mistakes in this
first, there is a trigger tag, its easier to understand triggers with it.

Quote:
Trigger:
Unit Group Bad
Events
Conditions
Collapse Actions
Collapse Unit Group - Pick every unit in (Units in (Playable map area)) and do (Actions)
Collapse Loop - Actions
Unit - Kill (Picked unit)
Now this will leak memory for every unit picked, which, depending on how many times this is ran, can add up heavily.
this doesnt create units, it adds all the units to the group and then runs the code, so the group leaks, not the units.

Quote:
Trigger:
Point Bad
Events
Conditions
Collapse Actions
Unit - Create 1 Footman for Player 1 (Red) at (Center of (Playable map area)) facing Default building facing degrees
The unit created at the region leaks. This is not a major leak, but depending on the amount of units created, and how often, it can add up.
the unit is not created at the region, but in the location, Center of (Region) returns a location.
also, the best way is not to use locations at all, there are alternative functions that take x and y reals.


Quote:
One last thing that can be done to completely remove memory leaks is that of nullifing your variables. If handlers are not nullified, then they will point to nothing, and still leak some memory.
this only concerns local variables.
02-04-2006, 10:23 PM#3
emjlr3
1. but doesnt it leak more for every unit picked?

say it would leak more if there were 1 unit picked as opposed to 50?

in any case, what is wrong with the unit group leak section?

2.its still a location leak, correct?, and why bother using x and y with GUI?

in any case, what is wrong with the location leak section?

3. I was told other wise by Daelin, if that is not the case I will change it back


im sad, this was accepted......:( then taken back

and ill fix up GUI tags when I get the chance
02-04-2006, 10:26 PM#4
Vexorian
Quote:
1. but doesnt it leak more for every unit picked?

say it would leak more if there were 1 unit picked as opposed to 50?

Nope. Maybe a group object takes much more space if it has more units. But that's something to test later. Either way it is only one group object leaking.
02-06-2006, 04:22 AM#5
emjlr3
updated to comply with suggestions
02-14-2006, 05:45 AM#6
TGhost
What if i just create a unit at lets say Center of Playable Map Area.
How do i destroy that memory leak? And is there even one here?
02-15-2006, 12:50 AM#7
emjlr3
Code:
         Point Good
Events
Conditions
Actions
Set Temp_Point = (Center of (Playable map area))
Unit - Create 1 Footman for Player 1 (Red) at Temp_Point facing Default building facing degrees
Custom script: call RemoveLocation (udg_Temp_Point)

as stated in the tut.
02-18-2006, 04:49 PM#8
TGhost
no i meant if i just created a unit at the center of a region, without using any variables at all.
02-20-2006, 04:24 PM#9
emjlr3
I think since regions are preplaced into variables you dont need to set them, I may be wrong
02-20-2006, 04:30 PM#10
Vexorian
Center of (region) creates a new point that you must destroy.
02-21-2006, 06:41 PM#11
TGhost
but what is the costum script for that?
02-22-2006, 03:18 PM#12
emjlr3
removing an destroying it....did you even read the tut.?
02-28-2006, 04:43 PM#13
Chuckle_Brother
Just a quick mention about units. Just killing dummies often isn't good enough. You can still rack up some amazing lag just because of their nonexistant "corpse" sitting around, so you may also want to add a trigger that removes dummies as they die.
02-28-2006, 04:48 PM#14
emjlr3
an idea, but unless you have hundreds of units dying every minute I doubt this will be an issue

plus that doesnt really have to do with memory leaks now does it?
02-28-2006, 04:57 PM#15
Anitarf
Actually, if you set the unit's death type to "can't raise, Does not decay", then it leaves no corpse behind, and is removed from memory the moment it dies.

The tutorial still claims global variables should be nullified even though that's not the case.

On the topic of floating texts, I thought the destroy action destroyed them instantly, and the disable permanence action was the one used in conjunction with the lifespan action to destroy it over time.