Snapshot object has memory leak. Maybe...

local storyboard = require("storyboard") storyboard.isDebug = true timer.performWithDelay(1000, function (e) storyboard:printMemUsage() end, 0) timer.performWithDelay(1000, function (e) local snapshot = display.newSnapshot(100, 100) snapshot:removeSelf() snapshot = nil end, 0)

I found memory increase in my project.

I has spent many hours for finding memory leak and I found snapshot has memory leak.

How can i clean up snapshot?

This is because garbage collection doesn’t happen right away.  Look at this code instead:
 

local storyboard = require("storyboard") storyboard.isDebug = true storyboard:printMemUsage() local ss = {} for i = 1, 100 do     ss[i] = display.newSnapshot(100,100) end for i = 100, 1, -1 do     ss[i]:removeSelf()     ss[i] = nil end storyboard:printMemUsage() timer.performWithDelay(10000, function() storyboard:printMemUsage(); end, 1)

When it first runs, I have 263K of Lua memory used and 0 texture memory.

After creating and deleting 100 snapshots, the Lua memory has increased to 329K (probably the increase in the table allocation) and I have 5.376 megabytes of texture memory, which makes sense give that we’ve created 100 128x128x 4 textures.  But even though we’ve blown through the table and cleared it, garbage collection has not run yet, so the texture memory is still in use.

Upon finish, I see that my Lua memory has dropped a little bit from 329K to 313K. This is likely nil’ing the odd things in the table (but the table records still exist).  After 10 seconds we print the memory again after garbage collection has has time to run and my texture memory is back down to a lovely 0.0 where it started.

It’s really hard to use the tests like you’re doing to look for leaks.  It’s natural for your data to grow and shrink over time.  That’s not necessarily a leak.  Because garbage collection happens behind the scene it makes these tests

Rob.

local storyboard = require("storyboard") storyboard.isDebug = true storyboard:printMemUsage() local ss = {} for i = 1, 5000 do ss[i] = display.newSnapshot(4,4) end storyboard:printMemUsage() for i = 5000, 1, -1 do ss[i]:removeSelf() ss[i] = nil end storyboard:printMemUsage() timer.performWithDelay(3000, function() storyboard:printMemUsage(); end, 0)

I still doubt snapshot memory management .

Texture memory management is perfect but system memory is not perfect.

This sample makes garbage over 1Mbyte of system memory. Never garbage collected.

Of course, this sample is not a normally case but it proves that snapshot has some system memory problem.

If use other display object(image, container…etc), system memory is clean up perfectly.

Anyway, thanks for reply. Please make resolve this issue.

This block of code:

[code]

for i = 1, 5000 do
    ss[i] = display.newSnapshot(4,4)
end

[code]

creates a lua table that is 5000 entries big.  Even though you remove the objects and nil them, the table still holds 5000 nil’s.  If you do:

ss = nil

after you’re done freeing things up to blow away the table, does it shrink back down?  It may not shrink all the way because there may be meta tables or other things that Lua and API calls are doing under the hood.

This line:  timer.performWithDelay(3000, function() storyboard:printMemUsage(); end, 0)

is also creating a timer object which is still live and functioning while that function is running.  It’s really hard to try and look at memory management using examples like this.  They are not realistic usage and frequently what looks like leaks really are not leaks. 

Rob

This is because garbage collection doesn’t happen right away.  Look at this code instead:
 

local storyboard = require("storyboard") storyboard.isDebug = true storyboard:printMemUsage() local ss = {} for i = 1, 100 do     ss[i] = display.newSnapshot(100,100) end for i = 100, 1, -1 do     ss[i]:removeSelf()     ss[i] = nil end storyboard:printMemUsage() timer.performWithDelay(10000, function() storyboard:printMemUsage(); end, 1)

When it first runs, I have 263K of Lua memory used and 0 texture memory.

After creating and deleting 100 snapshots, the Lua memory has increased to 329K (probably the increase in the table allocation) and I have 5.376 megabytes of texture memory, which makes sense give that we’ve created 100 128x128x 4 textures.  But even though we’ve blown through the table and cleared it, garbage collection has not run yet, so the texture memory is still in use.

Upon finish, I see that my Lua memory has dropped a little bit from 329K to 313K. This is likely nil’ing the odd things in the table (but the table records still exist).  After 10 seconds we print the memory again after garbage collection has has time to run and my texture memory is back down to a lovely 0.0 where it started.

It’s really hard to use the tests like you’re doing to look for leaks.  It’s natural for your data to grow and shrink over time.  That’s not necessarily a leak.  Because garbage collection happens behind the scene it makes these tests

Rob.

local storyboard = require("storyboard") storyboard.isDebug = true storyboard:printMemUsage() local ss = {} for i = 1, 5000 do ss[i] = display.newSnapshot(4,4) end storyboard:printMemUsage() for i = 5000, 1, -1 do ss[i]:removeSelf() ss[i] = nil end storyboard:printMemUsage() timer.performWithDelay(3000, function() storyboard:printMemUsage(); end, 0)

I still doubt snapshot memory management .

Texture memory management is perfect but system memory is not perfect.

This sample makes garbage over 1Mbyte of system memory. Never garbage collected.

Of course, this sample is not a normally case but it proves that snapshot has some system memory problem.

If use other display object(image, container…etc), system memory is clean up perfectly.

Anyway, thanks for reply. Please make resolve this issue.

This block of code:

[code]

for i = 1, 5000 do
    ss[i] = display.newSnapshot(4,4)
end

[code]

creates a lua table that is 5000 entries big.  Even though you remove the objects and nil them, the table still holds 5000 nil’s.  If you do:

ss = nil

after you’re done freeing things up to blow away the table, does it shrink back down?  It may not shrink all the way because there may be meta tables or other things that Lua and API calls are doing under the hood.

This line:  timer.performWithDelay(3000, function() storyboard:printMemUsage(); end, 0)

is also creating a timer object which is still live and functioning while that function is running.  It’s really hard to try and look at memory management using examples like this.  They are not realistic usage and frequently what looks like leaks really are not leaks. 

Rob

Sorry to use the old post, But the problem seems still exist.
 

I use the following code to test:

for i = 1, 1000 do local snapshot = display.newSnapshot(100, 100) display.remove(snapshot) snapshot = nil end

And the result:

Dec 24 18:33:56.994: memUsage = 821.044 KB

Dec 24 18:33:56.995: texMemUsage = 10.004 MB

Dec 24 18:33:58.002: memUsage = 774.126 KB

Dec 24 18:33:58.002: texMemUsage = 10.004 MB

Dec 24 18:33:59.003: memUsage = 1260.154 KB

Dec 24 18:33:59.003: texMemUsage = 10.004 MB

Dec 24 18:34:00.019: memUsage = 1213.279 KB

Dec 24 18:34:00.019: texMemUsage = 10.004 MB

Dec 24 18:34:01.027: memUsage = 1213.279 KB

Dec 24 18:34:01.027: texMemUsage = 10.004 MB

Dec 24 18:34:02.035: memUsage = 1213.279 KB

Dec 24 18:34:02.035: texMemUsage = 10.004 MB

Dec 24 18:34:03.042: memUsage = 1213.279 KB

Dec 24 18:34:03.042: texMemUsage = 10.004 MB

Dec 24 18:34:04.051: memUsage = 1213.279 KB

Dec 24 18:34:04.051: texMemUsage = 10.004 MB

Dec 24 18:34:05.060: memUsage = 1635.154 KB

Dec 24 18:34:05.061: texMemUsage = 10.004 MB

Dec 24 18:34:06.068: memUsage = 1588.279 KB

Dec 24 18:34:06.068: texMemUsage = 10.004 MB

Dec 24 18:34:07.077: memUsage = 2138.154 KB

Dec 24 18:34:07.077: texMemUsage = 10.004 MB

Dec 24 18:34:08.084: memUsage = 2091.279 KB

Dec 24 18:34:08.084: texMemUsage = 10.004 MB

Dec 24 18:34:09.092: memUsage = 2091.279 KB

Dec 24 18:34:09.092: texMemUsage = 10.004 MB

The memory usage is increase every time when I run the above “for” loop. although it will release some memory after 1-2 second.
If I replace the “newSnapshot” to “newGroup”, no memory leak occur.

You cannot do these kinds of tests to “prove” a leak.  This simply isn’t how Lua’s garbage collection works.  Garbage collection runs in intervals and it’s not a fixed amount of time, there are many factors that trigger when Lua cleans up memory.  These type of “print memory usage” things only works over a long period of time and can’t be used to measure if one API call is leaking memory.

Rob

Thanks for your reply in Christmas. And sorry for the wordings that I descript the issue :slight_smile:
Is there any way to confirm that the memory will release?
For this, I have been tested with “collectgarbage” after the for loop, though it may not be the correct method. No memory release after collectgarbage.
And I tested with display group with object on it. The memory seems will release after 1-2 second.

By the way, one more suspected case is the nested object:
Scroll view -> display group -> scroll view

local baseScrollView = widget.newScrollView(viewOption)
local group = display.newGroup()
baseScrollView:insert(group)
local childScrollView = widget.newScrollView(viewOption2)
group:insert(childScrollView)

Sorry for just a part of code since I’m using mobile to reply.

If I just remove the base scroll view, the memory seems will not release. But if I remove the display group first, all created memory will be cleared.

Just want to make sure if the objects works normally before release the app.

Thanks and Merry Christmas

When I built my first Corona SDK based app, I lost a lot of sleep and stressed out over memory leaks.  I didn’t want my first app rejected and I did a lot of what you’re doing.  It takes time to learn what causes leaks and how to avoid them.  

You also have to have faith that Lua and Objective-C/Java are going to do the right thing for you.  One of the nice things about using a high level language like Lua vs. a lower level language like C is that you don’t have to manage your memory.  As long as you remove things when your done and nil them, the system will take care of them.

So many people do a tight loop test to try and prove a leak in Corona code and in 100% of the cases, the test isn’t taking Lua’s garbage collection schedule in to consideration.  It’s also an unrealistic way people use the code.  No one is going to make 1000 snapshots in a fraction of a second. 

What you should be worried about is the long term memory usage.  If you are not creating new things or you think you are disposing of everything properly, is your memory growing over time.

Rob

Before reply your message, I want to tell you more about what I’m doing:
I’m writing an post-base app, which will have lots of post display in scrollview. In order to understand the performance, I make a test with lots of post, let’s say, 1000 post, in the scrollview. After that, I need to know if I can remove all I created, so I run the remove objects and see if the memory usage is correct. But it failed. So I minimize the factors and find out that the problem may come from here. That’s why I post a question.

Sorry that my following reply maybe a little bit harsh.

For the second paragraph. I have faith that lua will help me to manage the memory correctly, so what I did first is to find out if I did anything wrong. But even I minimized the case, the problem is still here. So I asked here to see if I can have more evidence to prove that I can have “faith” on the system. A programmer should have a responsibility to find out if somewhere may have critical issue, but not in faith. For a user of Corona, it is also a responsibility to tell the developer of Corona that the potential problem may have. As a programmer, we cannot use “faith” as an only attitude.
Besides, I cannot make sure I can remove all I created if I don’t know which memory is created by me.

For the third paragraph. I’m not sure if I have enough consideration on garbage collection. I tried use function “collectGarbage”, but no use. I tried to waited for 5 minutes to see if the memory will release, but no use. That’s why I asked here to see if still anything I can do. By the way, I cannot find any relationship between the memory leak and the so-called “UNREALISTIC WAY TO USE THE CODE”. My intention is to test the performance if lots of objects on the screen. If too much objects is created in the same time will cause problem, I can try to create each object in every second, or even every minute. I just want to make sure if my application will works without critical issue.

Again sorry for my harsh comment. Hope you will understand why I reply in this way. And thanks for your sharing in the first paragraph and the useful advice in the fourth paragraph :slight_smile:

Please advice about the test.

For 7 days running of the following code:

local function garbagePrinting()collectgarbage("collect") local memUsage\_str = string.format( "memUsage = %.3f KB", collectgarbage( "count" ) ) print( memUsage\_str ) local texMemUsage\_str = system.getInfo( "textureMemoryUsed" ) texMemUsage\_str = texMemUsage\_str/1000 texMemUsage\_str = string.format( "texMemUsage = %.3f MB", texMemUsage\_str ) print( texMemUsage\_str ) end -- Runtime:addEventListener( "enterFrame", garbagePrinting ) local testSnapShot = {} local function createNewSnapshot() for i = 1, 10 do display.remove(testSnapShot[i]) testSnapShot[i] = display.newSnapshot(100, 100) local img = display.newImageRect("Image/img1.jpg", 200, 200) testSnapShot[i].group:insert(img) testSnapShot[i]:invalidate() end end createNewSnapshot() timer.performWithDelay(1000, createNewSnapshot, 0) timer.performWithDelay(1000, garbagePrinting, 0)

gives the following result:

Jan  6 12:37:17.237: memUsage = 990749.360 KB

Jan  6 12:37:17.238: texMemUsage = 3040.000 MB

Jan  6 12:37:18.484: memUsage = 990762.485 KB

Jan  6 12:37:18.484: texMemUsage = 3040.000 MB

Jan  6 12:37:19.732: memUsage = 990760.610 KB

Jan  6 12:37:19.733: texMemUsage = 3040.000 MB

Jan  6 12:37:20.967: memUsage = 990773.735 KB

Jan  6 12:37:20.967: texMemUsage = 3040.000 MB

Jan  6 12:37:22.220: memUsage = 990771.860 KB

Jan  6 12:37:22.220: texMemUsage = 3040.000 MB

Jan  6 12:37:23.477: memUsage = 990784.985 KB

Jan  6 12:37:23.477: texMemUsage = 3040.000 MB

Jan  6 12:37:24.714: memUsage = 990783.110 KB

Jan  6 12:37:24.714: texMemUsage = 3040.000 MB

Jan  6 12:37:25.955: memUsage = 990796.235 KB

Jan  6 12:37:25.955: texMemUsage = 3040.000 MB

Jan  6 12:37:27.182: memUsage = 990794.360 KB

Jan  6 12:37:27.182: texMemUsage = 3040.000 MB

Jan  6 12:37:28.426: memUsage = 990807.485 KB

Jan  6 12:37:28.426: texMemUsage = 3040.000 MB

Jan  6 12:37:29.682: memUsage = 990805.610 KB

Jan  6 12:37:29.682: texMemUsage = 3040.000 MB

Jan  6 12:37:30.921: memUsage = 990819.025 KB

Jan  6 12:37:30.922: texMemUsage = 3040.000 MB

Jan  6 12:37:32.161: memUsage = 990816.860 KB

Jan  6 12:37:32.161: texMemUsage = 3040.000 MB

Jan  6 12:37:33.398: memUsage = 990829.985 KB

Jan  6 12:37:33.398: texMemUsage = 3040.000 MB

Jan  6 12:37:34.639: memUsage = 990828.110 KB

Jan  6 12:37:34.639: texMemUsage = 3040.000 MB

Jan  6 12:37:35.906: memUsage = 990841.235 KB

Jan  6 12:37:35.907: texMemUsage = 3040.000 MB

Jan  6 12:37:37.152: memUsage = 990839.360 KB

Jan  6 12:37:37.153: texMemUsage = 3040.000 MB

Jan  6 12:37:38.395: memUsage = 990852.485 KB

Jan  6 12:37:38.396: texMemUsage = 3040.000 MB

Jan  6 12:37:39.652: memUsage = 990850.610 KB

Jan  6 12:37:39.652: texMemUsage = 3040.000 MB

Jan  6 12:37:40.891: memUsage = 990863.735 KB

Jan  6 12:37:40.892: texMemUsage = 3040.000 MB

I gave up. :ph34r:

Anyway, we will not use the feature.

He is looking at us as newbie worker, I trust Lua garbage collect more than his words.

I tried his code and really think that Corona has problem with display.newSnapshot

I simplified his code like that:

 local function garbagePrinting() collectgarbage("collect") local memUsage\_str = string.format( "memUsage = %.3f KB", collectgarbage( "count" ) ) print( memUsage\_str ) end timer.performWithDelay(2000,function() print("before create ------------------------") garbagePrinting() local a = display.newSnapshot(200,200) print("after create ---") garbagePrinting() timer.performWithDelay(1000,function() print("before remove ---") garbagePrinting() a:removeSelf() a = nil print("after remove ---") garbagePrinting() timer.performWithDelay(500,function() print("long after remove ---") garbagePrinting() print (" +++ ") end) end) end,0)

and here is the result: 

qSTGrbH.jpg

You can see memory slowly increase. You just need to modify line 11 from:

local a = display.newSnapshot(200,200)

to 

local a = display.newGroup()

and see no memory increase.

If it’s not a Lua leak, so what is difference between display.newSnapshot and display.newGroup ? Did I remove snapshot in the right way with removeSelf function?

local oneSecond = 1000 local tenSeconds = 10000 local function oncePerSecondMemoryCleanupAndReporting() -- -- perform two full garbage collection cycles -- collectgarbage("collect") collectgarbage("collect") -- -- report memory usage -- local mem = collectgarbage("count") print("Lua memory use: " .. mem .. "K") end timer.performWithDelay( oneSecond, oncePerSecondMemoryCleanupAndReporting, 0 ) local theSnapshot = nil local function oncePerTenSecondsCreateOrRemoveSnapshot() -- -- alternately create OR destroy the snapshot -- if (theSnapshot == nil) then theSnapshot = display.newSnapshot(100, 100) print("-- SNAPSHOT CREATED --") else display.remove(theSnapshot) theSnapshot = nil print("-- SNAPSHOT REMOVED -- ") end end timer.performWithDelay( tenSeconds, oncePerTenSecondsCreateOrRemoveSnapshot, 0 ) -- -- report a rough initial memory usage (to define those fns, create the timers, etc) -- collectgarbage("collect") collectgarbage("collect") local mem = collectgarbage("count") print("Initial/Baseline Lua memory use: " .. mem .. "K") -------------------------------------------------------------------------------- -- -- RUN FOR AT LEAST 100 FULL CREATE/REMOVE CYCLES -- -- what you'd like to see: -- all reports following removal stabilize toward some non-increasing value -- -- what you're likely to see: -- creating the snapshot consumes about .4K -- removing the snapshot releases about .2K -- thus gradual leak of about .2K per create/remove cycle

The bug report for this is:  Case 38123

Rob

Thanks, Rob