I’ve been poking around and I can’t seem to find anything on garbage collection and memory management. Questions:
Can it be forced? I saw there used to be a collectGarbage(), but I am unable to find it in the reference. I will be using a number of nonce images created and disposed of on the fly and I’d like to force gc on very large sets. I’m assuming setting an object to nil will mark it for collection.
In a stand-alone app, when the app is sent to the background, what sort of strategies are used to relinquish memory? Is garbage collected? is any part of the runtime unloaded? or, do Codea apps run in a 64K memory space?
@syntonica - to paraphrase the Lua docs, locals are stored in the VM registers and referenced by index. Globals on the other hand are stored in a table and are accessed using a hash lookup - which is much slower.
Thanks, Andy. Looks like I will have to save the running state regularly. I have no desire to poke around in Cocoa–last time I tried it, it was like a straightjacket.
@syntonica and @Dwight - there’s also some compelling arguments for tuning the garbage collector to be more aggressive regarding the frequency of how often it executes, rather than simply splattering your code with individual GC calls.
The collectgarbage command has 2 optional args for tuning the performance of how often it goes into garbage collecting mode (setpause and setstepmul) - the Lua docs (at lua.org) should give some more technical insight on how this works in practice.
It’s also worth mentioning that efficient use of local variables should reduce the need for extensive calls to GC as they use the stack for automatically releasing memory when no longer used (rather than via the main garbage collecting cycle).
Use of locals also has the additional advantage of speeding your code up as well.
@andymac3d. I haven’t looked under the hood at Lua yet to see how the VM has been implemented. When you say stack, I’m assuming the machine stack and not a virtual one?
Does Lua always use stack frames or will it optimize some locals to registers? Or, am I talking JIT compiling at this point?
Agreed that more aggressive gc can work if the code is regularly littering old objects. The shorter pauses should not be noticeable at all if a frame or two is dropped.
@syntonica - as for point 2. I guess there’s no easy way for your Lua code to know directly that once its compiled and running as an app that its been suspended.
You’ll probably need to hook in some Objective-C (via Xcode) that communicates the current App State to your code using the app object delegate when it transitions into the ‘background’ state before its suspended . You should be able garbage collect at this point before it goes to sleep.
Indeed, once suspended and if any foreground apps need additional memory resources (should it be running low) the system will purge suspended apps without warning.
Thanks, all. I think just forcing it between scene changes will be enough. Running a scene itself won’t generate trash, just destroying it.
Anything on my question #2? Do I need to worry about releasing memory at all if my app gets sent to the background? Or, do I just need to check if data structures need to be (re)built on method entry?
There is a collectgarbage function (might by garbagecollect or collectgarbage, I’m not sure) it just isn’t documented as far as I know,
I have been writing a large program with lots of states and lots of stuff on the screen. There is a state I can get my game in where it will consistently crash Codea if I leave it alone for about a min. I cant help but wonder if this is when the garbage collection is happening.
I have been poking around here and thought that maybe collectgarbage() sprinkled about might help me but it sounds like it mostly helps physics which I have none.
Is there other best practices for when to use collectgarbage() ?
I am no expert on garbage collection, but it makes a huge difference in some cases. It seems to run about every 60 seconds in Codea.
It has a very important effect with physics objects, where, if you delete references to them, they stay “alive” until the next collection, like zombies, that may interfere with other physics objects. You need to explicitly destroy physics objects before deleting their reference variables, so it is a two step process. This is documented in the physics:destroy function.
Codea’s documentation of Lua’s functions is nowhere near completely. I might spend some time committing parts to the Wiki docs sometime. Yo might also try my Objective C library for better automatic garbage collection (fixed most crashes in my app): http://twolivesleft.com/Codea/Talk/discussion/4221/objective-c-libraries%3A-testflight-gamecenter-location-twitter-facebook-camera-roll-sharing-more#Item_9
Hrm. Maybe I should have tried that then… brb
Back! Apparently, it’s collectgarbage(). I habitually CamelCase everything after using Java so long.
lua handles garbage collection automatically. but in some cases you want to take more control over it and force it manually at need. in this case call
sometimes you need to repeat the garbage collection cycle more than once, to achieve the desired effect. that’s why people like to call:
…when forcing lua’s GC.
if scene then --scene variable not empty
scene = nil --empty scene variable
collectgarbage() --force lua's GC cycle 3x
@syntonica the garbagecollector is a must when you use lots of graphics. Google it to know what are the functions and force it after you set big objects to nil.
@andymac3d. I just slogged through 100 pages learning Lua and now you want me to read more? :((
@Jmv38. That’s my plan.
I had a similar problem in my game, it didn’t crash but the memory seemed high. I use this to track the memory and FPS so I can always see the ‘state’:
local FPS = 60
local elapsedTime, memory = 0, 0
-- put below in setup()
-- Initialise our metric counter
elapsedtime = ElapsedTime
-- Put in Main draw func
if (ElapsedTime - elapsedTime > 1) then
memory = collectgarbage("count") / 1024
elapsedTime = ElapsedTime
FPS = FPS * 0.9 + 0.1 / DeltaTime
text(string.format("%.0fFPS %.1fMB", FPS, memory), WIDTH - 80, 64)
This webpage also helped me quite a lot:
I also had to trawl the code a LOT to find dangling references to objects which held other objects which held other objects etc.
Lua’s default garbage collection algorithm is not so well suited for high frame rate games (from what I have read), so a judicious use of collectgarbage(), especially after large objects have been dereferenced is probably necessary. I actually make a single collectgarbage() call every 10 seconds to give the VM a ‘nudge’ in the right direction…
@brookesi - nice link and some good ‘practical’ advice!
I’m a big advocate of the ‘garbage collect small and often’ school of thought for games - I guess this is pretty much the optimum solution when a game is running where large numbers of things are being created and destroyed, and then do a big forced garbage collect at a natural pause in the game, such as the end of a level.
Thanks for all the replies.
I tried the code @brookesi posted. It’s fun and interesting.
It doesnt stop my game from crashing. Even though it calls collectgarbage often. Is there documentation on collectgarbage somewhere? What dies it output? Does the output change based on the string you feed it?
just google “lua collectgarbage”, there’s no docs in Codea on it
@Ignatz thanks. Don’t know why I assumed it was a Codea thing.