Memory not collected

Hey All,
Applying a simple technique I use with c++/c#, I see no memory getting collected. Can anyone tell me why this is happening for such a simple example? Before alloc, mem says 87k. I then alloc 1000 rect and the mem jumps to 224k. Then dealloc the rects (in several different ways) and the last mem call still says 224k. (If I copy/paste the code and do the same thing twice I lose the same amount again)

Thanks,
Ted

[lua]
local sayMem = function()
collectgarbage()
print( "MemUsage: "…collectgarbage(“count”) )
–local textMem = system.getInfo( “textureMemoryUsed” ) / 1000000
–print( "TexMem: " … textMem )
end

sayMem()

local group = display.newGroup()

for i=1,1000 do
group:insert(display.newRect(0,0,i,i))
end

sayMem()

– unneeded but tried anyway
–for i=group.numChildren,1,-1 do
– local r = group[i]
– r:removeSelf()
– --group:remove®
– r = nil
–end

group:removeSelf()
group = nil

sayMem()

[/lua]
[import]uid: 73649 topic_id: 36988 reply_id: 336988[/import]

Hi there,

One reason for the confusion is that, after calling removeSelf() on your display group, you should wait a frame (or maybe two) to ensure that the cleanup actually occurs, before checking your memory usage. Try replacing your final call to sayMem() with timer.performWithDelay(100, sayMem), and you’ll see that much of your memory does get reclaimed.

However, when I tried it myself I was surprised to see a significant chunk of memory still not being reclaimed, and I’m not sure why that is.

  • Andrew [import]uid: 109711 topic_id: 36988 reply_id: 145222[/import]

Thanks Andrew -

I had tried something like that just didn’t wait long enough. So after 1000 rect we have lost 43k. This is a bit disconcerting. I like to understand up front how mem is handled. This is telling me that for rect at least I might need to pool them and reuse. And I feel like now I have to test every object type like this for its characteristics.

Nevertheless thanks for your quick response Andrew.

Thanks
Ted
[import]uid: 73649 topic_id: 36988 reply_id: 145226[/import]

The Lua garbage collector does not delete memory immediately, just like most garbage collected languages such as Java and .NET. This is actually a performance optimization because deleting and reshuffling the heap memory can be expensive.

If you want to force Lua to collect garbage, then call the [lua]collectgarbage()[/lua] function.
[import]uid: 32256 topic_id: 36988 reply_id: 145229[/import]

Hi Joshua,

Yes, I agree, which is why tedsdogs’s sayMem() function calls collectgarbage() (line 2), to force the garbage collection, before printing out the memory usage. So I don’t think that explains the puzzle.

  • Andrew [import]uid: 109711 topic_id: 36988 reply_id: 145231[/import]

Sorry. Didn’t notice [lua]collectgarbage()[/lua] was being called at the very top of your source code.

I know that never everything about a display object is completely removed until the next render pass. So I did a quick test with the following code…
[lua]
local sayMem = function()
collectgarbage()
print( "MemUsage: "…collectgarbage(“count”) )
end

local function onEnterFrame(event)
local group = display.newGroup()
for i=1,1000 do
display.newRect(group, 0, 0, i, i)
end
group:removeSelf()
group = nil
sayMem()
end
Runtime:addEventListener(“enterFrame”, onEnterFrame)
sayMem()
[/lua]

If you look at the log, notice that we’re *not* leaking memory on every render pass.
[import]uid: 32256 topic_id: 36988 reply_id: 145241[/import]

Hi there,

One reason for the confusion is that, after calling removeSelf() on your display group, you should wait a frame (or maybe two) to ensure that the cleanup actually occurs, before checking your memory usage. Try replacing your final call to sayMem() with timer.performWithDelay(100, sayMem), and you’ll see that much of your memory does get reclaimed.

However, when I tried it myself I was surprised to see a significant chunk of memory still not being reclaimed, and I’m not sure why that is.

  • Andrew [import]uid: 109711 topic_id: 36988 reply_id: 145222[/import]

Thanks Andrew -

I had tried something like that just didn’t wait long enough. So after 1000 rect we have lost 43k. This is a bit disconcerting. I like to understand up front how mem is handled. This is telling me that for rect at least I might need to pool them and reuse. And I feel like now I have to test every object type like this for its characteristics.

Nevertheless thanks for your quick response Andrew.

Thanks
Ted
[import]uid: 73649 topic_id: 36988 reply_id: 145226[/import]

The Lua garbage collector does not delete memory immediately, just like most garbage collected languages such as Java and .NET. This is actually a performance optimization because deleting and reshuffling the heap memory can be expensive.

If you want to force Lua to collect garbage, then call the [lua]collectgarbage()[/lua] function.
[import]uid: 32256 topic_id: 36988 reply_id: 145229[/import]

Hi Joshua,

Yes, I agree, which is why tedsdogs’s sayMem() function calls collectgarbage() (line 2), to force the garbage collection, before printing out the memory usage. So I don’t think that explains the puzzle.

  • Andrew [import]uid: 109711 topic_id: 36988 reply_id: 145231[/import]

Sorry. Didn’t notice [lua]collectgarbage()[/lua] was being called at the very top of your source code.

I know that never everything about a display object is completely removed until the next render pass. So I did a quick test with the following code…
[lua]
local sayMem = function()
collectgarbage()
print( "MemUsage: "…collectgarbage(“count”) )
end

local function onEnterFrame(event)
local group = display.newGroup()
for i=1,1000 do
display.newRect(group, 0, 0, i, i)
end
group:removeSelf()
group = nil
sayMem()
end
Runtime:addEventListener(“enterFrame”, onEnterFrame)
sayMem()
[/lua]

If you look at the log, notice that we’re *not* leaking memory on every render pass.
[import]uid: 32256 topic_id: 36988 reply_id: 145241[/import]

Hi there,

One reason for the confusion is that, after calling removeSelf() on your display group, you should wait a frame (or maybe two) to ensure that the cleanup actually occurs, before checking your memory usage. Try replacing your final call to sayMem() with timer.performWithDelay(100, sayMem), and you’ll see that much of your memory does get reclaimed.

However, when I tried it myself I was surprised to see a significant chunk of memory still not being reclaimed, and I’m not sure why that is.

  • Andrew [import]uid: 109711 topic_id: 36988 reply_id: 145222[/import]

Thanks Andrew -

I had tried something like that just didn’t wait long enough. So after 1000 rect we have lost 43k. This is a bit disconcerting. I like to understand up front how mem is handled. This is telling me that for rect at least I might need to pool them and reuse. And I feel like now I have to test every object type like this for its characteristics.

Nevertheless thanks for your quick response Andrew.

Thanks
Ted
[import]uid: 73649 topic_id: 36988 reply_id: 145226[/import]

The Lua garbage collector does not delete memory immediately, just like most garbage collected languages such as Java and .NET. This is actually a performance optimization because deleting and reshuffling the heap memory can be expensive.

If you want to force Lua to collect garbage, then call the [lua]collectgarbage()[/lua] function.
[import]uid: 32256 topic_id: 36988 reply_id: 145229[/import]

Hi Joshua,

Yes, I agree, which is why tedsdogs’s sayMem() function calls collectgarbage() (line 2), to force the garbage collection, before printing out the memory usage. So I don’t think that explains the puzzle.

  • Andrew [import]uid: 109711 topic_id: 36988 reply_id: 145231[/import]

Sorry. Didn’t notice [lua]collectgarbage()[/lua] was being called at the very top of your source code.

I know that never everything about a display object is completely removed until the next render pass. So I did a quick test with the following code…
[lua]
local sayMem = function()
collectgarbage()
print( "MemUsage: "…collectgarbage(“count”) )
end

local function onEnterFrame(event)
local group = display.newGroup()
for i=1,1000 do
display.newRect(group, 0, 0, i, i)
end
group:removeSelf()
group = nil
sayMem()
end
Runtime:addEventListener(“enterFrame”, onEnterFrame)
sayMem()
[/lua]

If you look at the log, notice that we’re *not* leaking memory on every render pass.
[import]uid: 32256 topic_id: 36988 reply_id: 145241[/import]

No worries, thanks Josh.

Yup, I agree that there isn’t an ever-growing memory leak each frame, which would be a huge problem if there were, and surely not the first time it would’ve come up! :slight_smile: But what’s still a bit strange to me is that there does seem to be a permanently higher memory usage plateau after creating some display objects and then properly removing them, as if not all the memory is being reclaimed.

Here’s an I think even simpler example that illustrates what tedsdogs post was about.

[blockcode]
local sayMem = function()
collectgarbage()
print( "MemUsage: "…collectgarbage(“count”) )
end

sayMem()

local group = display.newGroup()
display.newRect(group, 0, 0, 1, 1)
group:removeSelf()
group = nil

sayMem()
[/blockcode]

When I run the above, the first memory printout is 102.779, but the second is slightly higher 103.011, even though the objects were removed. That suggests that some memory isn’t being reclaimed. (The exact numbers will probably vary depending on your machine and which device you simulate.)

If you then add a few more rectangles (i.e., copy/paste line 9 a few times), and the difference between the memory usage in the first and second printout gets even larger. The growth in the before/after difference appears to scale linearly (by about 0.12 in my case) for each new rectangle.

  • Andrew [import]uid: 109711 topic_id: 36988 reply_id: 145256[/import]

Fair enough. This is probably worth looking into further on our end too.

I do know that Lua internally uses hash tables to store all references and I have to wonder that it does not get reduced in size after removing objects. That is, the data gets deleted, but the reference table that tracks all objects remains the same size. That’s typically of hash tables. In any case, that’s my guess as to what is happening… assuming of course that Corona is not pushing unnecessary data into Lua. [import]uid: 32256 topic_id: 36988 reply_id: 145456[/import]

Thanks Josh.

Yeah, what you describe definitely sounds like a possible explanation. It’d explain why the memory growth is basically linear too. I’d be interested if you find out anything more.

  • Andrew [import]uid: 109711 topic_id: 36988 reply_id: 145476[/import]

Hi there,

One reason for the confusion is that, after calling removeSelf() on your display group, you should wait a frame (or maybe two) to ensure that the cleanup actually occurs, before checking your memory usage. Try replacing your final call to sayMem() with timer.performWithDelay(100, sayMem), and you’ll see that much of your memory does get reclaimed.

However, when I tried it myself I was surprised to see a significant chunk of memory still not being reclaimed, and I’m not sure why that is.

  • Andrew [import]uid: 109711 topic_id: 36988 reply_id: 145222[/import]