| 05-08-2004, 12:56 AM | #1 |
What Are Memory Leaks Memory Leaks are leakage of handle objects...that is...all objects excluding: Integers (including: Unit-Types, Item-Type and AbilityID), Reals, Booleans and Strings. That is: When you create a object, and you lose the reference of it, so it falls out of reach, and is thus a leaked piece of memory that won't be cleaned until the map finishes (thus, adds to exiting times). Which Leaks Should I Be Concerned With? Only the leakage of objects you dynamically create...that is...objects that get temporarely created in-game. So no need to worry about pre-placed units, regions, triggers and players (all these are still handle objects). In the end, you mostly need to worry about two object-types...these are: Locations and Unit Groups. Where/When Does It Leak. The thing is... EVERY time...in the Trigger Editor...when you are making an action...and you open up one of those GUI window labeled "Point"...and select something in it "except" a variable... a point will be created for you, but will "leak" becouse you don't catch it and dispose of it when you're done. Same lies with Unit Groups, all the actions in that GUI window, except the "Last Created Unit Group" one, will leak the unit-group they create. These are the 2 most serious things, as they are the type you use the most (think about every time you use the actions: Center Of Rect, Position Of Unit, Pick All Units In ... And Do Action - All these are leaking unless you catch the created objects and dispose of them properly). Player Groups are also created a few times, but not as often. However, they can be handled using the same way as mentioned further down. Then there are also the "temporary" Units and Special Effects one creates. And to a even lesser extent, one sometime creates: Regions, Timers, Timer Dialog Windows, Temporary Dialog Windows, Temporary Multiboards, Temporary LeaderBoards, Floating Texts, Sounds and Visibility Moderators. But these are most of the time way too rare to care about. And there is a certain rule of thumb, if the trigger runs only once (or just rarely), you don't need to worry about it.. But if it's a common trigger, like a periodic event, or something big....or if it's a trigger where you're Looping alot, then you should go through it and cover up all memory leaks in it. So How Do I Then Clean Up Memory Leaks? Blizzard gave us a bunch of functions to destroy these created objects...but unfortunately, they didn't add them to the GUI :P. So basicly, you have 2 options... You can either; * Use Custom Script actions to use the Blizzard natives in JASS, or... * Get WEU or UMSWE...as they have these actions included in GUI This tutorial explains both. What you do is. First: you create 1-2 Point variables named something like: TempPoint, and a Unit Group variable named similarely... Then, whenever you see yourself selecting something from a Point window or a Unit Group window except in a "Set Variable" action... you have to instead do the following: Code:
Set TempPoint = (Center of UnitSpawn <gen>) Unit - Create 1 Footman for Player 1 (Red) at TempPoint facing Default building facing degrees Custom script: call RemoveLocation( udg_TempPoint ) So you can basicly see that I moved the "(Center of UnitSpawn)" action, to a "Set Variable" action. Then after using it, you destroy it. Note, that in UMSWE, it would look like the following: Code:
Set TempPoint = (Center of UnitSpawn <gen>) Unit - Create 1 Footman for Player 1 (Red) at TempPoint facing Default building facing (270.0) degrees Point - Remove TempPoint This works the same for Unit Groups and Player Groups. Except you change the last line too (if you're using the Custom Script action): Code:
Custom script: call DestroyGroup( udg_TempGroup ) Code:
Custom script: call DestroyForce( udg_TempForce ) //Force = Player Group UMSWE and WEU have both of these actions. Now, it's generally the same thing what you do with "Temporary Units" and Special Effect. But luckily, WE has a action for destroying these. Depending on wether there is a Wait action between the point where you create your special effect, and where you want to destroy it...you can set "Last Created Special Effect" in a special effect variable, then just use: Code:
Special Effect - Destroy TempSFX You can also just use that action on "Last Created Special Effect" if there is no wait involved (but I guess that's rare). Note, that...since two triggers could be using the same SFX variable at the same time...you should try to either have a controlled access to these variables....or better...derive Local variables for you to use. But that's something I won't cover in this tutorial. But yeah, Removing Units work the same way. To be safe, you might wanna first Kill the unit, then Remove it, as there have been problems with Removing units directly in certain situations (if it's hidden f.ex.). (Oh, and all rumors about "Removing Units" leaking tons of memory are wrong. There isn't even much sense in that anyways, so Removing Unit is a secure thing to do (as I say, just to be safe, kill the unit first)). And for all the other types I mentioned above...in most of the cases there is a GUI action for destroying it. One Last Tip In triggers that run only once (Initialization Triggers and Cinematic Triggers), you can add to the end of it the following action to destroy it, people have reported that it's quite effective. Code:
Custom Script: "call DestroyTrigger(GetTriggeringTrigger())" or Code:
Trigger - Destroy (Triggering Trigger) if you're using UMSWE/WeU Anyhow, that's it. ~Cubasis |
| 05-08-2004, 01:59 AM | #2 |
whoah thats amazing my map is gonna run 90% smoother now thnx to u!! ur awesome! |
| 05-08-2004, 05:06 AM | #3 |
Cubasis, nice explanation. If i'm using point many times, do u think its a good idea to make one point var and use move point to x,y action everytime i need a point? i mean in terms of leakage it should be fine? thank. |
| 05-14-2004, 09:56 AM | #4 | |
Quote:
You don't move points, well unless you want to. You set point = whatever u want, use it, destroy it. onto the next one. you can use one variable for every point if you destroy it before you use it agian, otherwise it will leak. |
| 05-19-2004, 07:06 AM | #5 |
Well, moving point's is completely fine, however, its also pretty useless. I mean, memory-wise, it's just the same, as one way you're just creating the point again and destroying it almost instantly, and the other way you're always using the same point to move it around (so the difference would be this single point, as the first way would "at times" have 1 less point in memory - However, that is NOT something to worry about). Although..., performance wise, moving the point is technically MORE efficient than constantly creating and destroying it. HOWEVER .... if you worry about that piece of performance .... you should stop working in GUI, becouse guess what ... most all the actions in GUI are ....screened natives ... that is, a function in blizzard.j that simply swaps parameters (or not even that much) before calling the "true" native. Which is ofcourse just a waste of calls. And to add, not even JASS guru's worry about the efficiency loss from creating/destroying points, as it's just so tiny. Oh, and then there is another thing... all the functions like PolarProjection, GetUnitLoc etc already create the location.... so you wouldn't profit at all unless you create your own set of function .... that move a location instead of returning it. So at that point, it would be easier for ya to just learn JASS completely and drop Locations in terms of X/Y reals :P. Conclusion: .... just destroy the friggin points :D ~Cubasis |
| 05-19-2004, 06:18 PM | #6 |
Nice tut. Good description of leaks and why they happen, and how to get rid of them. Well written and easy to understand. Pretty helpful, although I dont often get leaks. 350 Posts! Yeah!! |
| 05-31-2004, 10:28 PM | #7 |
Thanks for this tut. It's awesome |
| 06-02-2004, 06:59 PM | #8 |
I think if you are constantly destroying/creating locations then moving is better. Code:
function foo takes nothing returns integer return R2I(Cos($FA)) + $DEAD endfunction function bar takes nothing returns nothing local integer i = $F local integer max = foo() loop exitwhen i > max set i=i+$A endloop endfunction |
| 06-03-2004, 01:49 PM | #9 |
Yes aiurs, that's true... But then you have to aquire all the x/y's for all the location you want to move too. Either by using the WE (which would work bad in loops unless you fill up a array (or 2, considering we have 2 reals to work with) with them) ... or, you can aquire the X/Y of units/rects whatever. But then one can wonder, which is in reality more efficient: Code:
loop exitwhen i >= max call MoveLocation(loc,GetRectX(udg_Rects[i]),GetRectY(udg_Rects[i])) ... set i = i + 1 endloop or Code:
loop exitwhen i >= max set loc = GetRectCenter(udg_Rects[i]) ... call RemoceLocation(loc) set i = i + 1 endloop The first one uses "three" function calls... although 2 of these are cheap accessors and the third is a simple method. While the second calls "two" function calls ... where both may be a bit heavyer as they're assigning and destroying memory. So generally, at this point of performance-concern, you better not (as I said above) be using ANY blizzard.j interface functions. Anyways, the main thing is also... that... This article/tutorial is pointed to the GUI triggerer that wants to get rid of leaks in his map. GUI doesn't even have Move Point by default -_-. So they'd need to learn JASS (atleast a bit) to get some use out of this. And at that point, they'd also need to learn that extra piece on memory leaks (local handle leaks). Anyways, I realize this post may sound a bit harsh, so don't take it too seriously. ~Cubasis |
| 06-04-2004, 02:06 AM | #10 | |
Quote:
Wait..does that mean that set udg_temppoint = GetUnitLoc(GetTriggerUnit()) call Something with udg_temppoint call RemoveLocation(udg_temppoint) will still leak? If so... foooooooooooooooooook. Lol. That will mean time to go through all my triggers and do x of unit y of unit. |
| 06-04-2004, 11:21 AM | #11 |
Ah, guess I confused you. No, everything I stated in my original post works completely to get rid of memory leaks. That post was only/mostly for the guy who thought of "moving" stuff instead of creating/destroying it. What I ment with that piece, is that.... GetUnitLoc (and all those functions) "create" a point automatically, and then return it. That's why you need to catch it (into a variable) and destroy it later. And the last statement was just talking about the alternative approach, how one can most of the time pass X/Y's to functions instead of locations. But that's alot more work and will likely just confuse people more. ~Cubasis |
| 06-04-2004, 10:51 PM | #12 |
Ok good..whew. |
| 06-06-2004, 01:34 AM | #13 |
What if i use GetSpellAbilityUnit() in like 20 trigs? cause i have a lot of trigger spells so i use it ALL THE TIME. should i get rid of those? Memory leaks are really annoying if you dont get em when ur first making the spell... ive made a bunch of trigs.. now i gotta go through and make them all mem leak free :( If we still had points you could get a ton for mem leak extermination... ooh.. and about like leader and multiboards... i saw something about removing the items.. is that right after you create them or when you destroy the multiboard?? cause dont you need them for the multiboard? or once you set it your dont need the vars anymore? |
| 06-06-2004, 01:49 AM | #14 |
As far as I know, that doesnt leak. It returns a unit. However, GetSpellAbility(was it with or without the ability.. forgot)TargetLoc() does leak.. that returns a location. |
| 06-06-2004, 01:54 AM | #15 |
One more question, what do you mean temp units? like you create a unit then get rid of it? do you use RemoveUnit? cause that kills the unit... |
