| 10-15-2003, 09:43 PM | #1 |
Maybe a list of known causes memory leaks would be helpful? Here's what I found so far: Removing units (doh) PauseUnit returning location (more?) handles through jass functions Not destroying objects when they should (doh) --> GUI This means that some functions in common.j and Blizzard.j leak by simply using them (PolarProjectionBJ for example). Everybody should avoid using these functions. |
| 10-15-2003, 10:50 PM | #2 |
What evidence is there that returning a function causes a memory leak? If that were true any map that used recursion would experience leaks -- I use it extensively in Battledome with locations and I don't have any leaks. |
| 10-17-2003, 06:50 PM | #3 |
A function (code) is not a handle. I've only tested this with location so far, but my guess is every handle leaks when returned. Also note that passing handles as parameters to other functions does not leak; I'm only talking about returning. |
| 10-17-2003, 08:18 PM | #4 |
I can't really see why handles would cause memory leaks when returned. They are just integers where the value of the integer specifies a place in an internal array of Warcraft. You can actually convert the handles into integers using a bug in the return type recognition. And since they are integers, why would returning them cause any leaks? There is no actual copy of the content made. |
| 10-18-2003, 03:34 AM | #5 | |
Quote:
How did you test it? My map returns a function that returns a location a few hundred times everytime I play my map with even a few people, and I haven't noticed any leaks. |
| 10-22-2003, 12:05 PM | #6 |
The setup: A trigger that fires when the player types "test". The action function contains a loop (1 to 10,000), and a local variable called "temploc". Boot war3 (Ctrl+F9 in WE). Open task manager with Ctrl+Shift+Escape and look at mem usage of war3.exe process. Then run loop once and check again. Then run loop 20 times and check again. Inside this loop I tested the following: Code:
function testlocals takes nothing returns location local location testloc = null set testloc = Location(10, 20) return testloc endfunction Loop set temploc = testlocals() call RemoveLocation(temploc) endloop Code:
function testlocals takes nothing returns location return Location(10,20) endfunction Loop set temploc = testlocals() call RemoveLocation(temploc) endloop Code:
function testlocals takes nothing returns location local location testloc = null set testloc = null return testloc endfunction Loop set temploc = testlocals() endloop Code:
function testlocals takes nothing returns location local location testloc = null set testloc = Location(10, 20) call RemoveLocation(temploc) endfunction Loop call testlocals() endloop Code:
Loop set testloc = Location(10, 20) call RemoveLocation(testloc) set testloc = Location(10, 20) call RemoveLocation(testloc) set testloc = Location(10, 20) call RemoveLocation(testloc) set testloc = Location(10, 20) call RemoveLocation(testloc) endloop This leaks only the first time it is run. Roughly 12 megs. The second time you run it, it doesn't leak anymore. Conclusions for now (more testing is needed to be certain): When no object is created, war3 doesn't leak. RemoveLocation doesn't clean up the entire object. However, in some cases the "left-overs" are recycled. The code for Interceptor movement in PR caused a nice leak because of this... |
| 10-22-2003, 01:37 PM | #7 |
I used this function, run by trigger once every second. Code:
local integer i=0
local location l
loop
exitwhen i > 10000
set l = mytest()
call RemoveLocation(l)
set i =i +1
set udg_count = udg_count +1
endloopAs you can see, I verify the number of times it has run. I had a timer recording elapsed time. Heres the results: It leaked approximately 600K each minute, during which time it ran about 518,000 times. The problem is thus: It's "leaking" about 1 byte each time the "mytest" function runs... If it was leaking handles, they should surely be 4 bytes and thus have a leak rate of something like 2meg a minute. But that still doesn't explain where the memory has actually gone... after all a "control" map with no units and only simple triggers doesn't leak 500K over a minute. I have a hunch it's something to do with the fact that the "testing" triggers arent running to completion (count was not a multiple of 10,000), so the triggers themselves are building up in the trigger queue and thus consuming memory. Unfortunately I dont know much at all about the trigger queue etc... |
| 10-22-2003, 01:43 PM | #8 |
It might be that the place in the array (or whatever it is) that is used to store all the handles is not recycled in the leaking cases. Try to convert the location into an integer and look how high that integer is at the last run of the loop. For converting use this: function Handle2Int takes handle h returns integer if h != null then return h endif return 0 endfunction |
| 10-22-2003, 05:43 PM | #9 |
I tried testing these functions. Notice the difference. This one leaks: Code:
function CreateLocation takes nothing returns location
local location a = Location(0, 0)
call RemoveLocation(a)
return a
endfunctionThis one doesn't leak: Code:
function CreateLocation takes nothing returns location
local location a = Location(0, 0)
call RemoveLocation(a)
set a = null
return a
endfunctionMy theory is that among other factors, Warcraft III avoids to assign a handle a new value if it suspects that there still might be a reference to that handle somewhere in the script. This way, the handle array gets huge. 1.9 million locations were created over several minutes using the first function, and the memory usage increased by 100 mb over the same period. The second method didn't have a noticable increase, so I didn't test it for as long. |
| 10-22-2003, 06:06 PM | #10 |
Another bug (but it's not causes memory leak) appears when adding special effect on dying unit just after death. Bug appears effect has unit stand animation model! After 5-10 minutes bug disappears. |
| 10-22-2003, 10:52 PM | #11 | |
Quote:
The setting to null thing sounds interesting tho. |
| 10-22-2003, 11:07 PM | #12 |
You can try this: function CreateLocation takes nothing returns location return Location(0, 0) endfunction 2 Peppar: I'm sorry, but second function returns location with coordinates (0,0), not null? I can't believe my eyes :) Is it really truth? |
| 10-22-2003, 11:15 PM | #13 | |
Quote:
|
| 10-23-2003, 01:08 PM | #14 |
If a script calls RemoveLocation, it means the programmer of the script tells the engine to destroy the location object. There is no reason to not destroy it. Also, RemoveLocation does remove the object, so any handle that might still point to the object is now invalid anyway. The set a = null sounds very interesting. If that works, I might have a solution for the memory leaks in my map :) The fact that the functions do not run to completion might have something to do with the memory leaks, if there is garbage collection going on at the end of a function, that doesn't happen when the function ends prematurely. That doesn't explain why some leaks only happen the first time you run the function though. |
| 10-23-2003, 01:22 PM | #15 |
Code:
function CreateLocation takes nothing returns location
local location a = Location(0, 0)
call RemoveLocation(a)
set a = null
return a
endfunction.. Or I just don't understand you? This function returns null anyway. So what is it for? |
