Some VERY basic questions below, but I'd like to check my understanding of scenemanager as I'm having a memory problem when changing scenes repeatedly with something I'm coding and it eventually cripples its performance. I'm very much a suck it and see hobby programmer and so my descriptions will be very non-technical I'm afraid.
I've sort of assumed that:
(1) If graphics and text are added using self rather than stage, then when the scene changes they will automatically be removed without me doing anything else.
(2) If I add an eventListener to a display object, then the listener will be removed when the object is.
Is that correct or will those leave something in memory?
Also, if I have tables of data in a scene, do those need to be cleared in any way? And what about sounds?
As a test, I've built by a simple thing that has almost identical code in two scenes and uses identical assets. Each scene has the option to either go to the other scene (e.g. scene1 to scene2) or to refresh itself by using scenemanager to go to itself again (e.g. scene1 to scene1). I'm using collectgarbage("count") to print out the memory use as each transition is completed.
I have found that whenever I go from a scene to itself (e.g. scene1 to scene1) the memory use stays pretty well constant. But, whenever I go back and forward between the two scenes, the memory use gradually increases. I've tried adding an enterFrame collectgarbage function and that made no difference. I've tried removing listeners as the transition is initiated and that made no difference! And I think it's the same problem that I'm experiencing in the proper app I'm coding.
Sorry for the long post, but any ideas welcomed!
Thanks, Pete
Comments
You need to watch for actions that increase memory usage (e.g. Texture.new()) and make sure you are only doing it once for each shared resource. I'm guessing that every time a scene is displayed on the stage it is increase memory usage.
This is all project management and I don't think it's the hardest part of making a game, since doing it wrong just makes the game buggy and it usually is the hardest thing to learn because it's so boring, complex, and unrewarding (lack of crashes is rewarding but it's a backwards incentive).
You should check out the game template since it's a larger project that does all of this stuff.
http://www.giderosmobile.com/forum/discussion/480/gideros-game-template
My apps: http://www.yummyyellow.com
But you're right, that's what my problem is. Thanks for all your suggestions.
ar2rsawseen, I've (hopefully) attached a zip file that contains the code and the assets for my test. If you could take a look at that, it would be great. It's two scenes, both of which show the set of numbers 0-9 one per screen if you scroll sideways using my rudimentary swipe code or tapping the edges of the screen. The red button on each screen swaps you between the two scenes. I've put a print statement in main.lua that prints out the memory use at the end of each transition. I find that the memory stays about the same as I scroll left and right but steadily and relentlessly increases if I keep swapping screens.
Thanks to both, Pete
I'm not sure why this is exactly, but I just spent more hours than I'd want to admit figuring out a similar memory leak that related to a self: enter frame event that would just pile up references to all the local images that were referenced inside the function it called, everytime the scene loaded. The function itself was also a local.
Another thing I have trouble with sometimes is I will need to remove an event listener as in this case, but unless the function is global it will be out of scope of the removeEventListener if I'm trying to call it in exitBegin for example. It might be nice if you didn't have to supply a function to removeEventListener and it just removed all listeners attached to that object (like self:removeEventListener(Event.ENTER_FRAME)
Anyway I'm pretty new at this still so every week I learn something that makes me realize I was doing it all wrong before, that's probably the case here :P
and sorry petec for hijacking your thread I hope ndoss' fix worked for you, I tested it and it worked as well.
I'm pretty sure that's whats actually happening. Maybe typing all that out made my brain work again... going to test it real quick.
Likes: avo
I think what I mentioned can be the case sometimes though since I ran into that problem with my own click events I was dispatching (things would happen twice). Yes I need to learn lessons multiple times before I remember anything apparently :P
Lets see if I can drill it in to my brain this time, remove event listeners every time all the time :P
So my assumption that the event listener would be removed when the scene was removed was wrong. Removing the listener certainly does the trick. I double checked by not removing the event listener in my swipeRight function and that produced a memory leak, so it obviously is that.
Now to go back to the proper thing I'm coding and hunt out all those event listeners.
Thanks, Pete
Edit: Oh look, just putting @ in front of a word does it.
I've just looked at the source code quickly and at first sight I think there shouldn't be any memory leak even if you don't remove the event listeners (but there is memory leak). I'll do some tests and try to find why these objects aren't GCed.
In fenceScreen.lua in attached file there are two lines (234 and 252) that are apparently causing memory leaks and I really don't know why. One sets the y scale of an object and the other sets alpha to 0. When the lines are commented out, going from the start screen to the fence screen and back again repeatedly causes the memory use to increase very slightly (why?) but if either of the two lines are uncommented, then they cause the memory use to increase more rapidly and keep going up, even if the function that they are in isn't called, which I don't understand.
I do wonder if it's something wrong that I'm doing with the way that I am generating multiple copies of objects as both the lines are referring to that type of object. The only thing that makes me wonder if that is the case is that if I change line 234 to
The code is quite flakey at the moment as I've taken out all my safeguards to make it easier to read, so it can lock up if you go backwards and forwards too quickly. Oh, and clicking the numbers splats the fence. With line 234 in action you can see where I'm going!
Any help welcomed, thanks
Pete
Just a small gripe about tabs, I can't easily see where fenceScreen:init() ends. After looking a little more I'm guessing the whole file is that function?
It looks like gotoMenuScreen is where all memory created by init should be cleared. Although I don't know for sure if you have to do this, I'd at least test it. In gotoMenuScreen I'd assign every variable that points to textures, sounds, fonts, etc to nil. See if that fixes it.
My apps: http://www.yummyyellow.com
I'll give your suggestion a go, although if nilling is needed I'm not sure why it would behave so differently when the commented lines are included or excluded. Also, I thought that when scenemanager removes the scene the variables were set to nil in that process, but I could well be wrong.
Thanks, Pete
Edit: Just to say that I've tried setting all suggested variables to nil before exiting the screen and it made no difference.
Memory management is complex but I think the hardest thing is knowing what types of behaviors should just be avoided and using discipline to allocate and release memory in consistent and predictable ways.
For example, a function like getWidth() should never ever allocate memory that isn't released, even if you have a function like cleanupGetWidth(). In 6 months you'll forget all about cleanupGetWidth() and you'll forget you need to call it.
As a rule of thumb, when I see .new() I always assume that memory is allocated and I need to nil it out. I don't know if lua or Gideros has any other functions that have memory allocation side effects, but that's what you are looking for.
Global variables could also be a culprit. The Lua garbage collector will only release something that has no variables pointing to it. So if you create a scene and store it in an global array and you just add scenes to that array then memory will increase. You obviously wont do that intentionally, but addEventListener might just do exactly this.
It's possible to go poking around all of the global variables. I had a script that did a great job printing the global namespace but I can't find it. Here is something simple to give you an idea of what you can do.
My apps: http://www.yummyyellow.com
@petec, I changed scene1.lua from your original problem and got rid of the removeEventListener that we had added to get rid of the memory leak -- the new version doesn't seem to have a memory leak even though it no longer removes the event listener. To do this, I converted all of your functions to scene1 class methods and changed some of the variables you'd defined as locals to be class variables. I believe that doing this in your second example would also fix its problems.
I couldn't quite get my head around the exact problem, but I think the problem you have with both posted examples is related to closures and the following pattern in your code:
Here's the changed version of scene1 that doesn't require the explicit removal of the event listener.
I've got a lot to learn, starting with trying to get my head round classes. I can see that your code above actually makes it easier to deal with the various functions than the way I have been writing it.
The one thing I'm not 100% sure of in the above is why the changeSceneBtn is added as
Thanks, Pete
if you store variable in self.someprop as example, then you can access it in any other class method. Say it's a way to use value in class scope - in all it's methods.
It would be possible to add event handler to both variables
In the following code, scene1 has a circular reference which I think Gideros should be able to handle deleting so I'm back to thinking it might be a problem in Gideros ... @atilim would have to say for sure.
Likes: avo, atilim, chipster123
thank you @ndoss for working on this to get such a simple example of the potential issue.
@ndoss thanks for carrying on looking at the problem.
The outcome is as you predicted - it got rid of the large memory leak I had before and it behaves just the same regardless of whether the two previously troublesome lines are commented out or included. It is still creeping up about 1 unit per visit, but that's what it did before with the lines commented out, so I guess that might be the other problem you have identified(?).
Anyway, thanks again for all of your help.
Pete
I've finally found the bug and corrected it. It only occurs when a listener function refers to the self as an upvalue (exactly as @ndoss's code)
Thank you
Likes: avo, GregBUG, Chang, cubuspl42