| 05-05-2005, 03:46 PM | #1 |
When do I need to set a handle or any of its subtypes to null to prevent memory leaks? Do I need to do it after every RemoveLocation() and Destroy...() call? |
| 05-05-2005, 04:07 PM | #2 |
You should do at before a function ends and only for local variables ( arguments for some reason don't need this) It doesn't matter if you don't destroy the handle it seems. And of course if you want to destroy the handle you have to do that before setting the variable to null |
| 05-05-2005, 04:19 PM | #3 |
Ok, so basically I check all handle-type/subtype local variables in every function & trigger and set their values to null at the end of the function (or before any return statement), and I'm ok? |
| 05-05-2005, 09:40 PM | #4 |
Yes, but not doing it isn't such a big deal. What do I mean? Let say you create a unit and do some modulation to it inside the function Code:
function Foobar takes nothing returns unit local unit u=CreateUnit(...) SetUnitSomething(...) return u endfunction Code:
function Foobar takes unit u returns unit set u=CreateUnit(...) SetUnitHp(...) return u endfunction whereby the unit is a bullshit pointer. Ofcourse if you really give this much of a damn...well then I suggest this which doesn't require the b.s. pointer but does require H2I. Code:
function Foobar takes nothing returns unit local unit u=CreateUnit(...) local integer i=H2I(u) SetUnitSomething(...) set u=null return i return null endfunction |
| 05-05-2005, 10:50 PM | #5 |
So, you eliminate the leak from the local unit by seting it to null, ok, I get that, it's standard procedure (and with unit groups and points, you must destroy them before seting the variable to null)... and the leak from the local integer is eliminated by returning null after you return the integer? That's because you can't set things to null after the return statement, if I remember correctly from another thread? So, any object (unit, unit group, location...) can be returned mem-leak free using either the b.s. pointer, or by converting it's handle to integer and returning that, and after that returning null? Sorry if I got it all wrong, but I'm still learning about how JASS (and object oriented programming in general) works, and I figure if I'm ever going to need it, it will be for some massive systems (like calculating backstab on every attack, that sort of stuff) that will definitely need to be memory leak free. |
| 05-05-2005, 11:18 PM | #6 |
Local Atomic types (int,real,boolean) are cleared of memory alocated at the end of a function. Local Handle Types (everything else except string and code) are only cleared of memory alocated if they are not pointing to anything. This means, an integer does not leak, but a unit can. The leak is very small, because it is a pointer leak. This statement: local unit u=CreateUnit(...) Does three things. First it creates a local pointer. It creates an index on the handle stack (this is the value you get when you H2I(u) ), and it creates the unit it self. Now if you remove the unit, your problems are solved right? Not quite. The Index won't be recycled if there are any pointers to it. However, jass is also retarded and decided that pointers, local or otherwise, won't be deleted if they are pointing to a handle index and not 0 (null) So in actuality, the pointer and the index still exist at the end of the function, even if the unit is removed in it. Now why isn't this such a big deal? First of handle indexs are never deleted. They are always at best recycled. Let say you have 10 player deatchmatch with no new units spawning. Once the units are vanquished the handle indexs will not be reset, even if they have no pointers pointing to them. Also most of the time, your function is running on a protagonist type unit, a main character. So that unit isn't being removed at all. So keeping his index "alive", by one extra local pointer shouldn't matter as you probably already have a pointer for him. Another thing to add to the stop worrying tab, is that a local pointer is thought to be around 4-16 bytes (four being how much is should actually be, and around 16 gotten by an estimate by AIAndy). Lets assume the worst and say it is 16. You would need to leak 62,500 pointers for even one meg of added ram abuse. Now, of course if it is perserving an unused handle index that can start adding up though. A handle index is around 40-50kb in size. Even then you'd need about 200 to start caring. Don't take this as a meaning to leak like a whore though. This is just one leak that isn't that big of a deal. Still get rid of locations and groups. EDIT: The return null is part of a technique an exploit in the jass checker. It doesn't check if all returns types are the one they are supposed to be, only if the last one is. |
| 05-06-2005, 12:09 AM | #7 |
Wait, is this the infamous "return bug" that I've heard mentioned before in relation to H2I? Basically you return an integer, but hide that from the syntax checker so it doesn't know that and doesn't cause problems with functions that require a unit (or some other handle type) parameter? And, to recap, local atomic types don't leak a thing and may be used to my heart's desire? However, in order to allow a handle index to be recycled, I must destroy that handle's object (with DestroyGroup, RemoveLocation and such) and also all local pointers that point to it (by setting them to null). But it's different with global pointers, somehow?... because in mem leak tutorials it doesn't state anywhere you would have to set a global variable to null after you destroy the handle object it was pointing to (such as a unit group) to prevent the memory leak. Edit: ahh, never mind, it makes sense to me now that things are the same for all pointers, but globals are globals, you will most certainly re-use them eventually to point to something else and at that point the handle previously pointed to will be "free", that's why it's only the locals we need to worry about. |
| 05-06-2005, 12:27 AM | #8 |
H2I, is the quintessential return bug function. Basically, you got the idea with the globals. A global will be reassigned, so you don't have to worry about it maintaining a handle index. You ideally should set it to null right after destroying it, but if you don't you'll probably reassign it so the handle index will be considered free when a new object is creating. |
| 05-06-2005, 11:57 AM | #9 |
Ok, the third case: arguments. Lord Vexorian said that you don't need to set handle type arguments to null after destroying their contents. Do you agree? |
| 05-06-2005, 12:12 PM | #10 |
Ok, I want some confirmation for these: Code:
function DuplicateLoc takes location loc returns location
return Location( GetLocationX(loc) , GetLocationY(loc) )
endfunctionCode:
//Used to get the target location in an area when the area is changed to another without a triggering unit (e.g. through the area menu)
function GetAreaTargetLoc takes integer pIndex, integer targetregion returns location
local group g = null
local location loc = null
local integer i = 0
//Select a hero from the region
set g = GetHeroesInRectOfPlayer(udg_Area[targetregion], Player(pIndex-1))
if ( IsUnitGroupEmptyBJ( g ) == true ) then
//call DisplayTimedTextToForce( GetPlayersAll(), 5.00, "Target Region Index (GetAreaTargetLoc): "+ I2S(targetregion) )
if targetregion == udg_DumAturRegion then
//if Dum Atur Yard
set loc = DuplicateLoc(udg_DefaultPlayerPoint[pIndex])
//call DisplayTimedTextToForce( GetPlayersAll(), 5.00, "Dum Atur Default Point" )
else
set loc = GetRectCenter(udg_Area[targetregion])
//call DisplayTimedTextToForce( GetPlayersAll(), 5.00, "Rect Center" )
endif
else
//select the first hero
set loc = GetUnitLoc(FirstOfGroup( g ))
//call DisplayTimedTextToForce( GetPlayersAll(), 5.00, "Hero Unit Loc" )
endif
call DestroyGroup( g )
set g = null
set i = H2I(loc)
set loc = null
return i
return null
endfunction |
| 05-06-2005, 02:50 PM | #11 |
Weeaddar is alive? Anyways, not setting it to null is not big deal unless the function is used a lot of times in really consecutive processes, That's why this leak is specially bad on blizzard.j's multiboard item functions. DuplicateLoc won't leak at all unless you don't Remove its returned location once you no longer need it |
| 05-06-2005, 04:24 PM | #12 |
Don't let the secret out. But yeah, its not terribly big leak so thats why its okay. Its also better if its referencing handle indexs which won't be dying anytime. e.g. function Objects takes nothing returns gamecache if (udg_gc==null)then set udg_gc=InitGameCache("blah.w3v") endif return udg_gc endfunction function foo takes integer s returns integer local gamecache gc=Objects() local integer i=GetStoredInteger(gc,"foo","bar") call StoreInteger(gc,"foo","bar", s ) return i endfunction the gamecache handle leak isn't significant at all, as that handle index is almost certainly to be still in use for a long while after. |
| 05-06-2005, 04:29 PM | #13 |
if handle is leaks what about all function with handle parameter, isn't that mean it's leak too ? |
| 05-07-2005, 12:10 AM | #14 | |
Quote:
|
| 05-07-2005, 01:23 PM | #15 |
How do you detect the leak ? Is Blizzard confirmed that there is a leak(bugs) in local handle ? |
