HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Why does blizzard create a temp point?

01-09-2004, 05:55 AM#1
Lil Blue Smurf
Okay, I am learning some stuff from the blizzard td, but I have a question. Why do they create a temp point everytime they do a move event and then delete it rather than just using random point in region, which is what the temp point is? If you just order a unit to go to random point in region does it create a mem leak, where as making a temp point doesn't? I am quite confused as it seems to be unnescesary coding.
01-09-2004, 07:41 AM#2
Grater
It is precisely to prevent a memory leak.
01-09-2004, 07:56 AM#3
Squashy
Grabbing a random point in a rect stores the point in memory indefinetly?
01-09-2004, 07:57 AM#4
Grater
Okay heres the long and the short of it, if you DONT manually assign a location to a variable and destroy it then it IS leaked. There are no exceptions. THe same is true for many other non-basic types (integers, reals, unit etc), Unit groups, SFX, Floating Text, all must be manually destroyed even it looks like it doesn't.

*** WARNING ***
There is one case when you must not destroy variables, if you have two variables (be they locations, or unit groups or whatever) and do:
Set A = B

Then A and B are now the same variable, changing one changes the other, destroying one destroys the other, because they are the same - this is also true if B is an elemant of an array. In fact you should never set one variable to another, if you want to copy a location you can use the GUI actions like
A = "Point with Offset(B, 0.0, 0.0)"

For unit groups you do something odd like:
Clear A
Copy all units from Unit group B to Unit Group A

Anyway thought I better add that warning because assigning one variable directely to another is bad practise and will almost certainitely lead to seemingly inexplicable bugs which are very uncool.
01-09-2004, 09:40 AM#5
Lil Blue Smurf
Okay, so why do you have to destroy the variable everytime? if you set temppoint = to random location, what is wrong with leaving it set to that until it is changed? does that still cause mem leak?
01-09-2004, 10:07 AM#6
Grater
Okay lets see if I can explain it, a Point or UnitGroup variable in the GUI is actually a pointer to the actual object in memory. Calling RemoveLocation/DestroyGroup frees that memory.

Now when you assign the variable to a new UnitGroup the one it was originally pointing to is lost to the void - there is nothing pointing to it and no way for you to get it to destroy it. But it is still there, taking up a small amount of memory and even if you want to clean it up you cant because you've lost track of it by reassinging the variable.

When WC3 loses track of millions of Locations (or Unitgroups, or SFX...) they start taking up a considerable amount of memory, possibly forcing Windows to use virtual memory and resulting in grinding performance. Memory leaking is rarely a problem on machines with 512MB of ram because theres a nearly limitless supply of memory, but on a machine with 128MB it's the difference between playable and laggy as hell, on a low memory system every object leaked ends up paged to the harddrive (disk chatter, slow), then when the game ends and WC3 automatically cleans up all the memory leaks, the leaked memory has to be paged back from the harddrive to the memory - resulting in the large lag at the end of games.

In reality only triggers that run very often can leak a significant amount of memory, triggers on rapid periodics, "unit dies", "unit is attacked", "unit uses an ability" etc are the main ones to clean up. A couple of locations leaked in your map initlization trigger is not going to matter.
01-09-2004, 06:55 PM#7
Newhydra
Are you sure of that grater? It's not very hard to write a "smart" pointer class, which seems like the logical thing for blizzard to have done...'course I haven't tested it so...
01-09-2004, 09:12 PM#8
Grater
I'm very sure that blizzard does not use a smart pointer class or garbarge collection - except for emergency garbage collection and I'm not sure what exactly that cleans up.

The simplist way to prove what I say is to create a very simple trigger:
Code:
Leak like crazy
    Events
        Time - Every 0.50 seconds of game time
    Conditions
    Actions
        For each (Integer A) from 1 to 5000, do (Actions)
            Loop - Actions
                Set TempLoc = (Position of Peasant 0001 <gen>)
                [color=grey]Custom script:   call RemoveLocation(udg_TempLoc)[/color]

Try it with and without the Custom Script action enabled, if using Win2K or WinXP compare memory usage by using the Task Manager. Also note how much longer it takes to leave the game without the remove action. (You'll only need to stay in the game for about 20 seconds to get a very noticable effect)

For me it leaks about 90,000KB in 25 seconds, when the destroy action is enabled it "leaks" about 600KB in 600 seconds (the leaking version would crash long before getting to 600 seconds)
01-09-2004, 09:33 PM#9
Xinlitik
So if a spell does a set target unit of ability being cast = Spelltarget, for instance, and you cast the spell a second time, it just loses track of the first one and it takes up memory? Or does it not work that way with specific units?

Also, if you have a Pick every unit going on a periodic timer, then every time it repicks, it stores the old one and eventually fills up memory?
01-09-2004, 09:48 PM#10
Newhydra
Not working that way for me grater. My trigger:
Code:
Melee Initialization
    Events
        Time - Every 0.50 seconds of game time
    Conditions
    Actions
        For each (Integer A) from 1 to 5000, do (Actions)
            Loop - Actions
                Set tmp = (Region centered at (Position of Peasant 0000 <gen>) with size (100.00, 100.00))
                Custom script:   call RemoveRect(udg_tmp)

I used RemoveRect because RemoveLocation gave a compile error.
(something about it not accepting a rect...I dunno where blizzard hid blizzard.j in the new version or I'd go look at what it wants...)

Both with and without the last line it leaks memory at about the same rate(100,000k after 30 sec)...However, I'll agree with you that war3 doesn't have any automatic clean up...
01-09-2004, 09:58 PM#11
Lil Blue Smurf
Well, for one, his trigger was creating a location, or point, not a region, so that has something to do with it. And thanks for the info, I'll be sure to do temppoints now :D
01-09-2004, 10:04 PM#12
Newhydra
Oh, was thinking he meant region when he said location...from SC

Using regions and removerect does not affect memory usage, at least it didn't for me. Using points and removelocation does reduce memory usage, however.
01-10-2004, 12:44 AM#13
Grater
Quote:
So if a spell does a set target unit of ability being cast = Spelltarget, for instance, and you cast the spell a second time, it just loses track of the first one and it takes up memory? Or does it not work that way with specific units?
Yup, thats right. All functions that return a point (location) return a new point. Say you get "Position of casting unit", it doesnt give you direct access to the position of the unit, if you change the variable it doesn't move the unit. It copies the location of the unit and returns that. It's your copy to do whatever you want with, and the responsible thing to do is destroy it when your done with it.

Quote:
Also, if you have a Pick every unit going on a periodic timer, then every time it repicks, it stores the old one and eventually fills up memory?
Memory leaking has nothing to do with "pick every unit", it's to do with the "in unit group part".
You can use as many "pick every unit" actions in unit group global variables as you like without any problems at all.

Code:
Set i = (Number of units in (Units owned by Player 1 (Red)))
What leaks here is the group "Units owned by Player 1 (Red))), just as if instead of counting the units you did something to each one with "pick every unit"

If for example you decide to manually keep track of a players units with something like this (not that it's nessecary):
Code:
Unit Enters
    Events
        Unit - A unit enters (Playable map area)
    Conditions
        (Owner of (Triggering unit)) Equal to Player 1 (Red)
    Actions
        Unit Group - Add (Triggering unit) to PlayerOnesUnits

Unit Dies
    Events
        Unit - A unit owned by Player 1 (Red) Dies
    Conditions
    Actions
        Unit Group - Remove (Dying unit) from PlayerOnesUnits
You can do whatever pick/count/add actions you want with "PlayerOnesUnits" without causing any memory leaks.
It is when you do something like:
Code:
Unit Group - Pick every unit in (Units owned by Player 1 (Red) matching (((Matching unit) is alive) Equal to True)) and do (Actions)
that you get the memory leak, it's the temporary unit group that leaks.

Now blizzard implementated a hack to help solve memory leaks, adding the line:
set bj_wantDestroyGroup = true
before various unit group actions will clean up the memory leak (then reset wantDestroyGroup to false). Note usage:
RIGHT
Code:
Custom Script: set bj_wantDestroyGroup = true
Unit Group - Pick every unit in (Units owned by Player 1 (Red) matching (((Matching unit) is alive) Equal to True)) and do (Actions)
        ...
Good usage, a temporary unit group is created, and then destroyed after it's used, just as it should be.


DISASTER
Code:
Custom Script: set bj_wantDestroyGroup = true
Unit Group - Pick every unit in (PlayerOnesUnits) and do (Actions)
        ...
Destroying something you weren't meant to will break your map, in this case it destroys the unit group "PlayerOnesUnits" so any triggers using that variable will suddenly appear to stop working. (well, they DO stop working, but most the triggers are fine, it's the variable that has been corrupted)

Cleaning up "memory leaks" that arent memory leaks result in very frustrating bugs. This is one reason why those "in the know" about memory leaks are so relucatant to share the know, if newbies start adding "set bj_WantDestroyGroup=true" will-nilly before their pick every unit actions then they will break their triggers [then come crying to the forums]. I was stumped for days after accidentely "fixing" a "memory leak" caused my triggers to stop working, and I've had years of programming experience in c and c++. How is a total newbie possibly meant to be able to get it right?

So blizzard isn't really holding out on the GUI users by neglecting to add "RemoveLocation, DestroyGroup" actions to the GUI or even explain about them. And the JASS folk mostly contain the memory leak discussion to the AI/JASS forum for much the same reason. (The reason is probably something like "It's easier to simply accept laggy but working maps than to deal with confused newbies with broken maps...")
01-10-2004, 03:26 AM#14
Xinlitik
Thanks a bunch that cleared a lot up. :foot:

Just one more question:
Is it as simple as a unit group that doesnt have any global variables involved and uses something that creates a copy of a number of units is safe to use that destroy hack?
01-11-2004, 05:33 AM#15
Grater
If theres no unit group variables involved it is always safe to use the hack. Also some with unit group variables are safe (mainly if it doesn't make sense to use a temporary unit group as one of the variables)

Safe:
Code:
 Unit Group - Add all units of (Units of type Footman) to TempGroup

Retarded:
Code:
 Unit Group - Add all units of TempGroup to (Units of type Footman)

Safe, but only cleans up one group leaving one to leak. The only way to make this action not leak is to use global (or local) unit group variables and DestroyGroup.
Code:
    Unit Group - Pick every unit in (Random 4 units from (Units of type Footman)) and do (Actions)