A mistake or a memory leak when removing display objects belonging to a group?

I am new to Corona and have noticed a small memory leak issue when I remove a group. The leak seems to persists when I remove each object belonging to the group and then remove the group itself. Every reference is also “nil”-ed in both cases. Of course there is the strong possibility that, as a novice, I am doing something wrong. Here is the code reproducing my problem. Does anyone have an idea of what is going on?

[code]


– main.lua


– MAIN LOOP FUNCTIONS

local getInfo
local wrapFunctionLeaky1
local wrapFunctionLeaky2

local function leacky1() – Execute first
for i = 1, 100 do
wrapFunctionLeaky1()
print (getInfo())
end
end

local function leacky2() – Execute second
for i = 1, 100 do
wrapFunctionLeaky2()
print (getInfo())
end
end


– wrapFunctionLeaky1()

function wrapFunctionLeaky1()

local line = display.newGroup()
local segment1 = display.newLine(100,100,200,200)
local segment2 = display.newLine(200,200,300,300)
local segment3 = display.newLine(300,300,400,400)
line:insert(segment1)
line:insert(segment2)
line:insert(segment3)

display.remove(line)
line = nil

end


– wrapFunctionLeaky2()

function wrapFunctionLeaky2()

local line = display.newGroup()
local segment1 = display.newLine(100,100,200,200)
local segment2 = display.newLine(200,200,300,300)
local segment3 = display.newLine(300,300,400,400)
line:insert(segment1)
line:insert(segment2)
line:insert(segment3)

display.remove(segment1)
segment1 = nil
display.remove(segment2)
segment2 = nil
display.remove(segment3)
segment3 = nil
display.remove(line)
line = nil

end


– getInfo()

function getInfo()
collectgarbage()
local memoryUsage = collectgarbage(“count”)
local textureMemoryUsage = system.getInfo(“textureMemoryUsed”)
return memoryUsage, textureMemoryUsage
end


– EXECUTE MAIN LOOP

leacky1()
print ("*** end leaky 1 ***")
leacky2()
print ("*** end leaky 2 ***")

[/code] [import]uid: 159908 topic_id: 30786 reply_id: 330786[/import]

@paolo,

I’m not sure if you need to nil out segment 1, 2, and 3 in wrapFunctionLeaky1 or not, it would be interesting to see if there is a difference.

I’m curious if you are working on a Win or Mac though.

FWIW, I don’t trust my memory leak #'s on my Win7 laptop, they consistently increase when I clear my display objects and create new ones. My app is a card game and I do this repetitively when each hand is finished. My Win7 memory leak was showing a value of about 40 kb/ hand. I struggled finding the leak for days in total confusion and panic. I then ran my app on my Mac Airbook and was surprised/relieved to see I had “0” memory leak from hand to hand…

As far as I’m concerned, the Win simulator is only good at showing gross leaks. From my experience, the output is suspect.

Nail [import]uid: 106779 topic_id: 30786 reply_id: 123242[/import]

@Nail,

I have tried your suggested change to wrapFunctionLeaky1: no change in the output.

The simulator is running on Mac with Snow Leopard. I am still on trial version of Corona. I haven’t gone as far as building for a device yet (before doing that I wanted to make sure that my fundamentals are “under control”).

Paolo [import]uid: 159908 topic_id: 30786 reply_id: 123246[/import]

@Paulo,

The good news is there is no memory leak if the function calls are slowed down.

I’m think the memory leak is being caused by to many processes being called to quickly, but not sure.

I replaced your getInfo() with the memory leak function I use that I found posted on this forum. It can be called with a Runtime listener and only udpdates the memCount if there is a change. It is much better than spamming the console with un-needed identical values and really helps when debugging.

You can comment out the Runtime listener and call the monitorMem() in the each function if you like. It works both ways.

I moved placed the monitorMem() below the leacky iterations. You were calling the getInfo() 100 times during the interation and may have been causing problems, really not sure.

I also slowed down the leacky function calls with a timer.

Here’s the modified code.

[code]------------------------------------------------------------------------------------------
– main.lua

–As is start= 91 / end = 204

–revised mem leak () Wind7: start = .1085 / end = .0978
–Mac: start = .0971 / end = .00879

– MAIN LOOP FUNCTIONS

local getInfo
local wrapFunctionLeaky1
local wrapFunctionLeaky2
local leacky1
local leacky2

–*************************

–This variation only prints changes in the memory status:

local prevTextMem = 0
local prevMemCount = 0
local memCount = 0
local monitorMem

function monitorMem()
collectgarbage()
memCount = collectgarbage(“count”) / 1024
if (prevMemCount ~= memCount) then
print( "MemUsage: " … memCount … “MB”)
prevMemCount = memCount
end
local textMem = system.getInfo( “textureMemoryUsed” ) / 1000000
if (prevTextMem ~= textMem) then
prevTextMem = textMem
print( "TexMem: " … textMem )
end
end
–You can commented out the Runtime listener and placed the () in Leacky1 & leaky 2 also
Runtime:addEventListener( “enterFrame”, monitorMem )

–*************************
–Memorory Leak Code Above<<<<<<<<<<<<

function leacky1() – Execute first
for i = 1, 100 do
wrapFunctionLeaky1()
–print (getInfo())

end
–monitorMem()
print( "leacky1 MemUsage: " … memCount … “MB”)

timer.performWithDelay(1000, leacky2)
print ("*** end leaky 1 ***")
end

function leacky2() – Execute second
for i = 1, 100 do
wrapFunctionLeaky2()
– print (getInfo())
end
–monitorMem()
print( "leacky2 MemUsage: " … memCount … “MB”)

timer.performWithDelay(1000, leacky1)
print ("*** end leaky 2 ***")
end


– wrapFunctionLeaky1()

function wrapFunctionLeaky1()

local line = display.newGroup()
local segment1 = display.newLine(100,100,200,200)
local segment2 = display.newLine(200,200,300,300)
local segment3 = display.newLine(300,300,400,400)
line:insert(segment1)
line:insert(segment2)
line:insert(segment3)

display.remove(line)
line = nil

end


– wrapFunctionLeaky2()

function wrapFunctionLeaky2()

local line = display.newGroup()
local segment1 = display.newLine(100,100,200,200)
local segment2 = display.newLine(200,200,300,300)
local segment3 = display.newLine(300,300,400,400)
line:insert(segment1)
line:insert(segment2)
line:insert(segment3)

display.remove(segment1)
segment1 = nil
display.remove(segment2)
segment2 = nil
display.remove(segment3)
segment3 = nil
display.remove(line)
line = nil

end


– getInfo()

function getInfo()
collectgarbage()
local memoryUsage = collectgarbage(“count”)
local textureMemoryUsage = system.getInfo(“textureMemoryUsed”)
return memoryUsage, textureMemoryUsage
end


– EXECUTE MAIN LOOP

leacky1()
–print ("*** end leaky 1 ***")
–timer.performWithDelay(500, leacky2)
–print ("*** end leaky 2 ***") [/code]

hope this helps,
Nail [import]uid: 106779 topic_id: 30786 reply_id: 123291[/import]

@Nail,

This is both very helpful and mysterious. :slight_smile: on one hand you have just proven that removing a display group is exactly the same as removing each child and the group (which is what I originally wanted to test – in my project i am nesting display groups and I only remove only the parent when I destroy the scene; however I am noticing a memory leak each time I change “scene”). On the other hand calling functions repeatedly and quickly yields inexplicable memory consumption.

I have run some quick test and it looks to me that calling functions one quickly after the other increases memory consumption in general. The problem is exacerbated when looping functions calls. I am running some other tests tomorrow. If my suspicions are confirmed, I will post the results.

In the meantime, thanks a lot for helping,
Paolo [import]uid: 159908 topic_id: 30786 reply_id: 123331[/import]

Garbage collection is not immediate. Sometimes it takes a few seconds. Call it on a touch listener, keep touching and watch the console output, you will most probably find that eventually it shows no leak. [import]uid: 160496 topic_id: 30786 reply_id: 123338[/import]

@Mike. That crossed my mind as well and, and Nail suggested, I have implemented an improved version of the memory monitor (“getInfo()”) as a runtime “enterFrame” listener. The listener updates the console only when memory consumption changes. This should be roughly equivalent to implementing it as a “touch” listener.

@Nail, my testing results as promised. We have established that the the two function (wrapFunctionLeaky1() and wrapFunctionLeaky2() ) are equivalent in terms of memory consumption, so I got rid of the second function, to simplify the code. I call wrapFunctionLeaky1() 100 times via the main function leaky1(). Then I call leaky1() 5 times in two different ways: MODE 1 will run the function 5 times 1/2 a second apart from each other; MODE 2 will run the function 5 time in “rapid sequence”. Memory consumption is higher in MODE 2 and will not go down even after a while. You can also comment out either MODE 1 or MODE 2 and run main.lua twice, as two separate projects. The result does not change for me: memory consumption is higher in MODE 2. That is strange and I do not understand this behaviour of Corona (or Lua?)

This is a problem for me because I call different views (and levels) as functions located in different modules. As the user navigates in and out of menus or even restarts a level, memory consumption goes up and up (not texture memory however). I am trying to figure out wether my programming style requires changing (in the usage of functions specifically).

[code]


– main.lua

– Mem leak MODE 1 (Mac): start = .1338 / end = .1241
– Mem leak MODE 2 (Mac): start = .1397 / end = .1403

– MAIN LOOP FUNCTIONS

– Fwd declarations
local getInfo
local wrapFunctionLeaky1
local leaky1

– Variables
local memoryUsageOld = 0

– Main function
function leaky1()
for i = 1, 100 do
wrapFunctionLeaky1()
end
end


– wrapFunctionLeaky()

function wrapFunctionLeaky1()

local line = display.newGroup()
local segment1 = display.newLine(100,100,200,200)
local segment2 = display.newLine(200,200,300,300)
local segment3 = display.newLine(300,300,400,400)
line:insert(segment1)
line:insert(segment2)
line:insert(segment3)

display.remove(line)
line = nil

end


– getInfo()

function getInfo()
collectgarbage()
local memoryUsage = collectgarbage(“count”)/1024
local textureMemoryUsage = system.getInfo(“textureMemoryUsed”)/1024
if (memoryUsage ~= memoryUsageOld) then
print(memoryUsage…" "…textureMemoryUsage)
memoryUsageOld = memoryUsage
end
return memoryUsage, textureMemoryUsage
end


– EXECUTE MAIN LOOP

Runtime:addEventListener(“enterFrame”, getInfo)

– MODE 1
leaky1()
timer.performWithDelay(1000, leaky1)
timer.performWithDelay(2000, leaky1)
timer.performWithDelay(3000, leaky1)
timer.performWithDelay(4000, leaky1)–]]

– MODE 2
local function batchCall()
print("*****************")
leaky1()
leaky1()
leaky1()
leaky1()
leaky1()
end
timer.performWithDelay(5000, batchCall)

[/code] [import]uid: 159908 topic_id: 30786 reply_id: 123387[/import]

@paolo,

This is a great exercise BTW, besides discovering what looks to be a memory leak with the rapid sequence function call.

I think I figured out what is happening.

Do this, comment out Mode 1 completely and replace Mode2 with this code. I moved the timer up into Mode2 and simply called batchCall() below it without a timer and see the output.

[code]
– MODE 2
local function batchCall()
print("*****************")
leaky1()
leaky1()
leaky1()
leaky1()
leaky1()

–you can replace the delay with 100 and see it performs identically :slight_smile:
timer.performWithDelay(2000, batchCall )
end

batchCall()[/code]

look at how the memory is not increasing with each execution of batchCall(0. This means there is no memory leak with the rapid sequence call. All the display objects and tables are being removed and nil’d as expected.

I hope you get the same values I’m getting, I’m working on a Win7 latptop with this BTW and getting a memory value of .12024…

I believe the larger initial memory value printed in the console with Mode2 , as compared to the value seen when firing Mode1 and having Mode2 commented out, simply represents the memory needed by Corona or lua to when it creates the tables required to register/reference the batchCall() itself.

One thing I realized when playing with this is the fact that we are NOT returning the segment display objects or the line display group when we are creating them and they are being removed properly with the display.remove(). Corona must be returning these automatically, I have always returned any display objects and groups when I create them in a function call. It looks like this is not needed from our results. I’ll probably continue to do this though, just to be sure, I do find it interesting we don’t have to return them at the bottom of the function though.

Another thing I saw, when I kicked an error playing with the exercise, was the diagonal white line we are actually spawning. I find is interesting we never see it displayed when running the code.

Do you understand and agree with my summation?

Hope this helps, it really had me scratching my head,

Nail
[import]uid: 106779 topic_id: 30786 reply_id: 123410[/import]

@ Nail,

I think (read “hope”) that I get this (thanks to your example). The fact that my 5 function calls are in the same lua-chunk of code (i.e. main) get the memory usage increases that we see (they are not a leak because I observe memory increasing BEFORE leaving the chunk). When you localise the group of 5 functions calls (via wrapping them into a separate chunk – i.e. function or a timer) then memory is cleaned after each execution of the chunk. So no leak, just measuring point error. Forcing garbage collection can only do one thing: collect garbage and not memory allocated to current chunk. Well, this is a good theory but I think I need to re-read Programming in Lua to validate (although your example seems quite definitive to me).

This leaves me with my issue of ever increasing memory when user navigates in and out of scenes. I will try and apply this theory when looking for potential causes. Fingers crossed. If I find something useful I will re-post here some artificial example.

Wrt returning display objects created inside a function, I can tell you what I understand of Corona’s mechanics. Please keep in mind that the terms that I use here are not necessarily correct and I have no insight into Corona source code. The “engine” is made of what you can mentally schematise as a series of “parallel loops”: “event reading and dispatching loop”, “non physics display refresh”, “physics display refresh”, etc. When you create a display object you use a “constructor”, i.e. a function creates what I believe is a lua table that holds lots of parameters and functions (keys are x, y, fill color, image path, reference point etc., values are whatever they are, and functions are stored in the table as well – i.e. “methods” such as setFillColor). The “constructor” registers such table with the “inventory” of Corona’s “non physics display refresh” loop. The loop goes through all the “registered” objects, loads data if it needs to (e.g. texture from a file) and displays objects in the order of “registration”. Objects are re-registered when inserted into a group (hence they go back to front when you use group:insert(object)). I bet that groups are special tables. In fact Corona has some sort of “super-parent” group where all display objects belong.

So the short answer is: an object pops up on your screen the minute you create it via the “constructor” (e.g. local obj_name = display.newImage()). The reference to the object (obj_name) needs to be returned if the object is still “alive” when you leave the chunk and the object is stored in a local variable created inside that chunk. My understanding is that without a reference you cannot access the objects anymore (e.g. you cannot remove it); but the object is still there. In this case we create and destroy the object in the same function so we do not need to care about keeping the reference “segment” or “line” (in fact we probably do not even need to nil the reference).

But hey, I am clearly having (hopefully small) memory problems with my code, so I clearly need to adopt a more “robust” programming technique.

Sorry for the long post, I always find it useful to go through the logic of what i think I have understood (it is the beginners forum after all; if I wasn’t thick I would post in other forums :slight_smile: ).

That was useful, thank you very much,
Paolo [import]uid: 159908 topic_id: 30786 reply_id: 123440[/import]

@paulo,

I just can’t believe I am constantly learning something new after months and months of working with Corona, lua and programing in general.

I really like your explanation why we don’t have to return the display objects because they are being spawned and destroyed in the same chunk, interesting. I’m glad I commented on not returning the objects/groups, I was confused why the memory use wasn’t climbing because of this. I haven’t played with any code similar to what we are doing here, spawning and destroying so many objects in so little time, in one chunk, I’m amazed it can be done actually.

It would be great if one of the more experienced developers would chime in here and comment on the exercise. I’ve actually wondered why the code uses ANY memory at all since everything is declared “local” from what I can tell.

You say your memory use is climbing between scenes in your app, I’'m wondering if there are tables, listeners, or timers linked to any of the objects that aren’t being cleared, even though the display references are being destroyed. I don’t believe just using display.remove(group) is good enough, there will still be tables that need to be destroyed/cleared by nil’ing out each object that is referenced.

[import]uid: 106779 topic_id: 30786 reply_id: 123466[/import]

@paolo,

I’m not sure if you need to nil out segment 1, 2, and 3 in wrapFunctionLeaky1 or not, it would be interesting to see if there is a difference.

I’m curious if you are working on a Win or Mac though.

FWIW, I don’t trust my memory leak #'s on my Win7 laptop, they consistently increase when I clear my display objects and create new ones. My app is a card game and I do this repetitively when each hand is finished. My Win7 memory leak was showing a value of about 40 kb/ hand. I struggled finding the leak for days in total confusion and panic. I then ran my app on my Mac Airbook and was surprised/relieved to see I had “0” memory leak from hand to hand…

As far as I’m concerned, the Win simulator is only good at showing gross leaks. From my experience, the output is suspect.

Nail [import]uid: 106779 topic_id: 30786 reply_id: 123242[/import]

@Nail,

I have tried your suggested change to wrapFunctionLeaky1: no change in the output.

The simulator is running on Mac with Snow Leopard. I am still on trial version of Corona. I haven’t gone as far as building for a device yet (before doing that I wanted to make sure that my fundamentals are “under control”).

Paolo [import]uid: 159908 topic_id: 30786 reply_id: 123246[/import]

@Paulo,

The good news is there is no memory leak if the function calls are slowed down.

I’m think the memory leak is being caused by to many processes being called to quickly, but not sure.

I replaced your getInfo() with the memory leak function I use that I found posted on this forum. It can be called with a Runtime listener and only udpdates the memCount if there is a change. It is much better than spamming the console with un-needed identical values and really helps when debugging.

You can comment out the Runtime listener and call the monitorMem() in the each function if you like. It works both ways.

I moved placed the monitorMem() below the leacky iterations. You were calling the getInfo() 100 times during the interation and may have been causing problems, really not sure.

I also slowed down the leacky function calls with a timer.

Here’s the modified code.

[code]------------------------------------------------------------------------------------------
– main.lua

–As is start= 91 / end = 204

–revised mem leak () Wind7: start = .1085 / end = .0978
–Mac: start = .0971 / end = .00879

– MAIN LOOP FUNCTIONS

local getInfo
local wrapFunctionLeaky1
local wrapFunctionLeaky2
local leacky1
local leacky2

–*************************

–This variation only prints changes in the memory status:

local prevTextMem = 0
local prevMemCount = 0
local memCount = 0
local monitorMem

function monitorMem()
collectgarbage()
memCount = collectgarbage(“count”) / 1024
if (prevMemCount ~= memCount) then
print( "MemUsage: " … memCount … “MB”)
prevMemCount = memCount
end
local textMem = system.getInfo( “textureMemoryUsed” ) / 1000000
if (prevTextMem ~= textMem) then
prevTextMem = textMem
print( "TexMem: " … textMem )
end
end
–You can commented out the Runtime listener and placed the () in Leacky1 & leaky 2 also
Runtime:addEventListener( “enterFrame”, monitorMem )

–*************************
–Memorory Leak Code Above<<<<<<<<<<<<

function leacky1() – Execute first
for i = 1, 100 do
wrapFunctionLeaky1()
–print (getInfo())

end
–monitorMem()
print( "leacky1 MemUsage: " … memCount … “MB”)

timer.performWithDelay(1000, leacky2)
print ("*** end leaky 1 ***")
end

function leacky2() – Execute second
for i = 1, 100 do
wrapFunctionLeaky2()
– print (getInfo())
end
–monitorMem()
print( "leacky2 MemUsage: " … memCount … “MB”)

timer.performWithDelay(1000, leacky1)
print ("*** end leaky 2 ***")
end


– wrapFunctionLeaky1()

function wrapFunctionLeaky1()

local line = display.newGroup()
local segment1 = display.newLine(100,100,200,200)
local segment2 = display.newLine(200,200,300,300)
local segment3 = display.newLine(300,300,400,400)
line:insert(segment1)
line:insert(segment2)
line:insert(segment3)

display.remove(line)
line = nil

end


– wrapFunctionLeaky2()

function wrapFunctionLeaky2()

local line = display.newGroup()
local segment1 = display.newLine(100,100,200,200)
local segment2 = display.newLine(200,200,300,300)
local segment3 = display.newLine(300,300,400,400)
line:insert(segment1)
line:insert(segment2)
line:insert(segment3)

display.remove(segment1)
segment1 = nil
display.remove(segment2)
segment2 = nil
display.remove(segment3)
segment3 = nil
display.remove(line)
line = nil

end


– getInfo()

function getInfo()
collectgarbage()
local memoryUsage = collectgarbage(“count”)
local textureMemoryUsage = system.getInfo(“textureMemoryUsed”)
return memoryUsage, textureMemoryUsage
end


– EXECUTE MAIN LOOP

leacky1()
–print ("*** end leaky 1 ***")
–timer.performWithDelay(500, leacky2)
–print ("*** end leaky 2 ***") [/code]

hope this helps,
Nail [import]uid: 106779 topic_id: 30786 reply_id: 123291[/import]

@Nail,

This is both very helpful and mysterious. :slight_smile: on one hand you have just proven that removing a display group is exactly the same as removing each child and the group (which is what I originally wanted to test – in my project i am nesting display groups and I only remove only the parent when I destroy the scene; however I am noticing a memory leak each time I change “scene”). On the other hand calling functions repeatedly and quickly yields inexplicable memory consumption.

I have run some quick test and it looks to me that calling functions one quickly after the other increases memory consumption in general. The problem is exacerbated when looping functions calls. I am running some other tests tomorrow. If my suspicions are confirmed, I will post the results.

In the meantime, thanks a lot for helping,
Paolo [import]uid: 159908 topic_id: 30786 reply_id: 123331[/import]

Garbage collection is not immediate. Sometimes it takes a few seconds. Call it on a touch listener, keep touching and watch the console output, you will most probably find that eventually it shows no leak. [import]uid: 160496 topic_id: 30786 reply_id: 123338[/import]

@Mike. That crossed my mind as well and, and Nail suggested, I have implemented an improved version of the memory monitor (“getInfo()”) as a runtime “enterFrame” listener. The listener updates the console only when memory consumption changes. This should be roughly equivalent to implementing it as a “touch” listener.

@Nail, my testing results as promised. We have established that the the two function (wrapFunctionLeaky1() and wrapFunctionLeaky2() ) are equivalent in terms of memory consumption, so I got rid of the second function, to simplify the code. I call wrapFunctionLeaky1() 100 times via the main function leaky1(). Then I call leaky1() 5 times in two different ways: MODE 1 will run the function 5 times 1/2 a second apart from each other; MODE 2 will run the function 5 time in “rapid sequence”. Memory consumption is higher in MODE 2 and will not go down even after a while. You can also comment out either MODE 1 or MODE 2 and run main.lua twice, as two separate projects. The result does not change for me: memory consumption is higher in MODE 2. That is strange and I do not understand this behaviour of Corona (or Lua?)

This is a problem for me because I call different views (and levels) as functions located in different modules. As the user navigates in and out of menus or even restarts a level, memory consumption goes up and up (not texture memory however). I am trying to figure out wether my programming style requires changing (in the usage of functions specifically).

[code]


– main.lua

– Mem leak MODE 1 (Mac): start = .1338 / end = .1241
– Mem leak MODE 2 (Mac): start = .1397 / end = .1403

– MAIN LOOP FUNCTIONS

– Fwd declarations
local getInfo
local wrapFunctionLeaky1
local leaky1

– Variables
local memoryUsageOld = 0

– Main function
function leaky1()
for i = 1, 100 do
wrapFunctionLeaky1()
end
end


– wrapFunctionLeaky()

function wrapFunctionLeaky1()

local line = display.newGroup()
local segment1 = display.newLine(100,100,200,200)
local segment2 = display.newLine(200,200,300,300)
local segment3 = display.newLine(300,300,400,400)
line:insert(segment1)
line:insert(segment2)
line:insert(segment3)

display.remove(line)
line = nil

end


– getInfo()

function getInfo()
collectgarbage()
local memoryUsage = collectgarbage(“count”)/1024
local textureMemoryUsage = system.getInfo(“textureMemoryUsed”)/1024
if (memoryUsage ~= memoryUsageOld) then
print(memoryUsage…" "…textureMemoryUsage)
memoryUsageOld = memoryUsage
end
return memoryUsage, textureMemoryUsage
end


– EXECUTE MAIN LOOP

Runtime:addEventListener(“enterFrame”, getInfo)

– MODE 1
leaky1()
timer.performWithDelay(1000, leaky1)
timer.performWithDelay(2000, leaky1)
timer.performWithDelay(3000, leaky1)
timer.performWithDelay(4000, leaky1)–]]

– MODE 2
local function batchCall()
print("*****************")
leaky1()
leaky1()
leaky1()
leaky1()
leaky1()
end
timer.performWithDelay(5000, batchCall)

[/code] [import]uid: 159908 topic_id: 30786 reply_id: 123387[/import]

@paolo,

This is a great exercise BTW, besides discovering what looks to be a memory leak with the rapid sequence function call.

I think I figured out what is happening.

Do this, comment out Mode 1 completely and replace Mode2 with this code. I moved the timer up into Mode2 and simply called batchCall() below it without a timer and see the output.

[code]
– MODE 2
local function batchCall()
print("*****************")
leaky1()
leaky1()
leaky1()
leaky1()
leaky1()

–you can replace the delay with 100 and see it performs identically :slight_smile:
timer.performWithDelay(2000, batchCall )
end

batchCall()[/code]

look at how the memory is not increasing with each execution of batchCall(0. This means there is no memory leak with the rapid sequence call. All the display objects and tables are being removed and nil’d as expected.

I hope you get the same values I’m getting, I’m working on a Win7 latptop with this BTW and getting a memory value of .12024…

I believe the larger initial memory value printed in the console with Mode2 , as compared to the value seen when firing Mode1 and having Mode2 commented out, simply represents the memory needed by Corona or lua to when it creates the tables required to register/reference the batchCall() itself.

One thing I realized when playing with this is the fact that we are NOT returning the segment display objects or the line display group when we are creating them and they are being removed properly with the display.remove(). Corona must be returning these automatically, I have always returned any display objects and groups when I create them in a function call. It looks like this is not needed from our results. I’ll probably continue to do this though, just to be sure, I do find it interesting we don’t have to return them at the bottom of the function though.

Another thing I saw, when I kicked an error playing with the exercise, was the diagonal white line we are actually spawning. I find is interesting we never see it displayed when running the code.

Do you understand and agree with my summation?

Hope this helps, it really had me scratching my head,

Nail
[import]uid: 106779 topic_id: 30786 reply_id: 123410[/import]

@ Nail
The problem was an enterFrame listener that will simply refuse to let me remove it. In short, when I remove , at the end of the level, either the object that that enterFrame listener is monitoring or the listener itself, I get a nil reference problem. If I do not run the code in debugger, then the code will run but the listener will cause anomalies. I will probably post an example of the issue in the physics forum one of these days. [import]uid: 159908 topic_id: 30786 reply_id: 123882[/import]

@ Nail,

I think (read “hope”) that I get this (thanks to your example). The fact that my 5 function calls are in the same lua-chunk of code (i.e. main) get the memory usage increases that we see (they are not a leak because I observe memory increasing BEFORE leaving the chunk). When you localise the group of 5 functions calls (via wrapping them into a separate chunk – i.e. function or a timer) then memory is cleaned after each execution of the chunk. So no leak, just measuring point error. Forcing garbage collection can only do one thing: collect garbage and not memory allocated to current chunk. Well, this is a good theory but I think I need to re-read Programming in Lua to validate (although your example seems quite definitive to me).

This leaves me with my issue of ever increasing memory when user navigates in and out of scenes. I will try and apply this theory when looking for potential causes. Fingers crossed. If I find something useful I will re-post here some artificial example.

Wrt returning display objects created inside a function, I can tell you what I understand of Corona’s mechanics. Please keep in mind that the terms that I use here are not necessarily correct and I have no insight into Corona source code. The “engine” is made of what you can mentally schematise as a series of “parallel loops”: “event reading and dispatching loop”, “non physics display refresh”, “physics display refresh”, etc. When you create a display object you use a “constructor”, i.e. a function creates what I believe is a lua table that holds lots of parameters and functions (keys are x, y, fill color, image path, reference point etc., values are whatever they are, and functions are stored in the table as well – i.e. “methods” such as setFillColor). The “constructor” registers such table with the “inventory” of Corona’s “non physics display refresh” loop. The loop goes through all the “registered” objects, loads data if it needs to (e.g. texture from a file) and displays objects in the order of “registration”. Objects are re-registered when inserted into a group (hence they go back to front when you use group:insert(object)). I bet that groups are special tables. In fact Corona has some sort of “super-parent” group where all display objects belong.

So the short answer is: an object pops up on your screen the minute you create it via the “constructor” (e.g. local obj_name = display.newImage()). The reference to the object (obj_name) needs to be returned if the object is still “alive” when you leave the chunk and the object is stored in a local variable created inside that chunk. My understanding is that without a reference you cannot access the objects anymore (e.g. you cannot remove it); but the object is still there. In this case we create and destroy the object in the same function so we do not need to care about keeping the reference “segment” or “line” (in fact we probably do not even need to nil the reference).

But hey, I am clearly having (hopefully small) memory problems with my code, so I clearly need to adopt a more “robust” programming technique.

Sorry for the long post, I always find it useful to go through the logic of what i think I have understood (it is the beginners forum after all; if I wasn’t thick I would post in other forums :slight_smile: ).

That was useful, thank you very much,
Paolo [import]uid: 159908 topic_id: 30786 reply_id: 123440[/import]

@paulo,

I just can’t believe I am constantly learning something new after months and months of working with Corona, lua and programing in general.

I really like your explanation why we don’t have to return the display objects because they are being spawned and destroyed in the same chunk, interesting. I’m glad I commented on not returning the objects/groups, I was confused why the memory use wasn’t climbing because of this. I haven’t played with any code similar to what we are doing here, spawning and destroying so many objects in so little time, in one chunk, I’m amazed it can be done actually.

It would be great if one of the more experienced developers would chime in here and comment on the exercise. I’ve actually wondered why the code uses ANY memory at all since everything is declared “local” from what I can tell.

You say your memory use is climbing between scenes in your app, I’'m wondering if there are tables, listeners, or timers linked to any of the objects that aren’t being cleared, even though the display references are being destroyed. I don’t believe just using display.remove(group) is good enough, there will still be tables that need to be destroyed/cleared by nil’ing out each object that is referenced.

[import]uid: 106779 topic_id: 30786 reply_id: 123466[/import]