Memory Leaks vs one-time cost

Curious about memory leaks. Initially, I was planning on asking why the below code (without the 2 commented out line) leaked. I’ve read about forward declaration and setting things to nil, but I just can’t wrap my head around why I’d have to set the local square to nil since it falls out of scope, thus removing any reference from my own code, and I was hoping display.remove(group) would take care of the rest.

However, what I noticed is that even with those 2 lines commented out, there appears to be a small leak. It’s not a typical leak though - it doesn’t keep growing. So I assume it’s just something fundamental I don’t understand, but what??

local storyboard = require('storyboard') storyboard.isDebug = true local group local function toggle() if group ~= nil then display.remove(group) group = nil else group = display.newGroup() for i = 1, 5 do -- local square = display.newRect(group, i \* 50, 50, 25, 25) -- square:setFillColor(0,0,0.5,1) end end end Runtime:addEventListener('tap', toggle) local function stats() collectgarbage() storyboard.printMemUsage() timer.performWithDelay(1000, stats) end stats()

You say “it doesn’t keep growing”, so in what way is it a leak? A leak is exactly that, where the memory usage keeps growing because an object is recreated without deleting the original or something like that.

The memory usage will always fluctuate up and down slightly, there are ‘behind the scenes’ things happening in corona that will cause it to go up and down. As long as it doesn’t keep going up indefinitely you should be fine.

That’s just wrong. Here’s a leak: 

void leak() {

  int *a = malloc(sizeof(int) * 10);

}

int main() {

  leak();

}

Maybe leaks that keep growing are more dangerous, but the above is a leak, and it can be plenty dangerous. A leak is when you’ve lost the ability to reclaim allocated memory, or for most languages with a GC, when memory is unintentionally rooted (an event handler holding on to a reference, a forgotten global…)

The above code somehow causes memory to be consumed, with no apparent way to release it. I’m fine if that’s a one time cost of doing something, but I’d like to understand that a little better than just taking it for granted. In particular, I’d like to know so that I can actually identify expected memory leaks for unexpected one.

Sorry, I thought I was replying to a post on the newbie forum so tried to keep it as simple as possible.  

You’re right about that code, it does increase the memory usage. When I start the program, my mem usage is:

System Memory Used: 0.270 Mb

then when I tap the usage goes up to:

System Memory Used: 0.272 Mb

If I comment out the for loop itself, it only increases to
 

System Memory Used: 0.271 Mb

So the creation of the for loop increases the memory with no way to claim that back. My guess would be that something in Lua doesn’t get loaded until a for loop is needed for the first time, but that’s purely speculation.

The extra 0.001 Mb must be the group being created, but then when it’s set to nil the memory doesn’t go down again, which I find odd.

Edit:

Just tried another test, and changed the toggle function to this:

local function toggle() local square = display.newRect( 50, 50, 25, 25) square:setFillColor(0,0,0.5,1) end

Not very tidy I know, but the memory usage increases by the same amount that it did when the group was created. Since both the newRect() and newGroup() functions belong to the display library, I’m guessing the memory usage is caused by display.* being called for the first time.

I also tried this:

local square = display.newRect( 50, 50, 25, 25) square:setFillColor(0,0,0.5,1) square:removeSelf( ) square = nil

outside of the toggle function, and the starting memory value was

System Memory Used: 0.271 Mb

which seems to support that idea.

You say “it doesn’t keep growing”, so in what way is it a leak? A leak is exactly that, where the memory usage keeps growing because an object is recreated without deleting the original or something like that.

The memory usage will always fluctuate up and down slightly, there are ‘behind the scenes’ things happening in corona that will cause it to go up and down. As long as it doesn’t keep going up indefinitely you should be fine.

That’s just wrong. Here’s a leak: 

void leak() {

  int *a = malloc(sizeof(int) * 10);

}

int main() {

  leak();

}

Maybe leaks that keep growing are more dangerous, but the above is a leak, and it can be plenty dangerous. A leak is when you’ve lost the ability to reclaim allocated memory, or for most languages with a GC, when memory is unintentionally rooted (an event handler holding on to a reference, a forgotten global…)

The above code somehow causes memory to be consumed, with no apparent way to release it. I’m fine if that’s a one time cost of doing something, but I’d like to understand that a little better than just taking it for granted. In particular, I’d like to know so that I can actually identify expected memory leaks for unexpected one.

Sorry, I thought I was replying to a post on the newbie forum so tried to keep it as simple as possible.  

You’re right about that code, it does increase the memory usage. When I start the program, my mem usage is:

System Memory Used: 0.270 Mb

then when I tap the usage goes up to:

System Memory Used: 0.272 Mb

If I comment out the for loop itself, it only increases to
 

System Memory Used: 0.271 Mb

So the creation of the for loop increases the memory with no way to claim that back. My guess would be that something in Lua doesn’t get loaded until a for loop is needed for the first time, but that’s purely speculation.

The extra 0.001 Mb must be the group being created, but then when it’s set to nil the memory doesn’t go down again, which I find odd.

Edit:

Just tried another test, and changed the toggle function to this:

local function toggle() local square = display.newRect( 50, 50, 25, 25) square:setFillColor(0,0,0.5,1) end

Not very tidy I know, but the memory usage increases by the same amount that it did when the group was created. Since both the newRect() and newGroup() functions belong to the display library, I’m guessing the memory usage is caused by display.* being called for the first time.

I also tried this:

local square = display.newRect( 50, 50, 25, 25) square:setFillColor(0,0,0.5,1) square:removeSelf( ) square = nil

outside of the toggle function, and the starting memory value was

System Memory Used: 0.271 Mb

which seems to support that idea.