Thursday, May 13th, 2010
The quote above was from a piece on the Palm Developer Center covering garbage collection in webOS.
With garbage collection, you get a boost in developer productivity…. but you always have to pay the tax man at some point. On mobile these issues are more astute so Mark Lam, a Principal Engineer in the webOS Platform team, goes into detail on V8 internals. The majority of the Q&A is applicable to anyone writing Web browser applications, on mobile or desktop.
- When does GC run?
- How are local variables stored? Are they ever on the stack? Do they get stuck into the activation record?
- When does the activation record for a function get collected? Is it just part of the regular GC cycles, or can it be collected when the function exits?
- How does the GC determine if my object is alive?
- Is it possible to have local variables get stuck into an activation record which result in a leak. If I stick a local variable into a global object, then do I have a global reference to my local activation record? If so, does this mean none of the local variables will get GC’d, or can one be moved out of the activation record without keeping the others around?
- What advice would you give developers to help them write code that lessens the possibility of triggering GCs? For example, say we’d really like to avoid creating garbage that might trigger GC while scrolling.
I love his detailed answers which give you a glimpse into the wonderful world of modern VMs. For example, his answer to the “How does the GC determine if my object is alive?” question:
- There are some global references called roots. These include system globals within V8, active stack frames, and persistent handles from the WebKit side.
- GC starts a scan from these roots. Whatever objects the roots reference will be kept alive.
- Next, GC scans the objects that have been found to be alive so far. Each of these objects in turn references other objects. Those objects will also be added to the keep-alive list.
- GC will keep re-iterating the keep-alive list (which eventually adds all live objects) until there are no more objects to be scanned.
- When there are no more objects to be scanned, any un-scanned objects are deemed dead.
- Next, GC scans weakrefs. Weakrefs are persistent handles that will be cleared automatically by GC if they are referring to objects that are no longer alive. Before clearing a weakref, GC will call a callback function (provided by the user who set up the weakref) to inform the app that GC is about to clear the weakref. After that, GC will clear the weakref and let the dead object be dead. The dead object gets collected on the next GC cycle, not the current one.
Note: User (non-V8) code can create a new persistent handle/ref to that object. In doing so, that object will become alive again in the next GC cycle. This is called resurrecting an object. (I don’t believe that webOS does any object resurrections.)
Weakref objects (which could be dead) are kept alive for the current GC cycle because GC needs to give the callbacks a chance to do some clean-up on their own side. There’s a chance that these callbacks may access information in the objects. While in the middle of a GC, the internals of objects may be altered and objects may be in the middle of moving. So GC waits until it is done with the current cycle before calling back the callbacks.
- Lastly, GC sweeps away all the dead objects and compacts memory.
What I described above is a simple mental model of how the GC works. The actual GC is a little more complex than that. But if you understand the above, you effectively know how GC works without all the nitty gritty details.
Posted by Dion Almaer at 6:55 am