Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2008-420
$eventId
ID of event: wwdc2008
$eventContentId
ID of session without event part: 420
$eventShortId
Shortened ID of event: wwdc08
$year
Year of session: 2008
$extension
Extension of original filename: m4v
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: [2008] [Session 420] Using Garba...

WWDC08 • Session 420

Using Garbage Collection with Objective-C

Essentials • 52:41

Garbage collection for Objective-C is an exciting technology that manages the memory in your application for you. By removing the worry of memory management, garbage collection allows you to simplify your code and focus on other aspects of your design. Discover how the garbage collector works, how to use zeroing weak references, how to take advantage of Foundation classes using garbage collection, and how to adopt best practices for using garbage collection in your own applications or frameworks.

Speaker: Patrick Beard

Unlisted on Apple Developer site

Downloads from Apple

SD Video (639.8 MB)

Transcript

This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.

Good afternoon. My name is Patrick Beard, and I work on the Objective-C runtime team, and I work on garbage collection. And I'm happy to be here today to tell you about garbage collection with Objective-C. So you're here. You're curious. Maybe you want to put a toe in the water.

Why use garbage collection? Garbage collection will give you faster development. You'll be able to spend less time thinking about memory management and more time thinking about program design. Memory leaks, gone. Crashes due to dangling pointers, gone, hopefully. And we provide tools that will help you visualize your program as it's running.

You can also get faster software because the code you write will be simpler. Less code hopefully means faster a lot of the time. The garbage collector can also be collecting memory, finding memory that's garbage that should be freed in the background. It runs concurrently with your program. And it's also sensitive to whether the user is actually doing something important. It can remain out of the way until the user pauses. And so perceived performance can go up.

And it's about time. It's about your time, saving you time while you write your code. It's about execution time. It's about making your programs run faster. And garbage collection has been around since the 1960s and has become increasingly popular with the languages like Java and C# that have been around for quite a while now.

So isn't it about time you use garbage collection? So the structure of the talk today, I'm going to talk about some high-level GC concepts. If you're not familiar with how garbage collectors work, I'm going to spend a little time showing you, giving you a mental model for how they work.

Then I'm going to spend some time talking about what's new in Snow Leopard. We have some exciting developments to talk about. Then I'm going to dive into the nuts and bolts, how to use garbage collection. How you can get the most out of it. Finally, I will spend some time on a demo, one of our-- a couple of our tools, and show you how to find out what's happening in a program and understand it, comprehend it better.

So let's dive into some garbage collection concepts. First off, what is a garbage collector? What to do? In this talk, I'm going to concentrate on using a garbage collector for managing your objects primarily. We're having a talk tomorrow at 2:00. Greg Parker is going to talk about how the garbage collector can also be used for lower-level tasks managing raw memory. But we're going to talk about objects primarily today. So another way to think about garbage collection beyond it being automatic memory management, automatic object management, is what it isn't.

With garbage collection, you can forget about reference counting. You can forget about bookkeeping, a bunch of details that can take a lot of your time to think about getting right. It means no dangling pointers. You can't over-release an object with garbage collection because there's no retain release to do. And on the other hand, no memory leaks. You can't over-retain an object. Thank you very much, or you're very welcome. So let's talk about the memory model in any garbage collected program with a little bit of emphasis on the Macintosh, Mac OS X.

Memory is divided up into three main areas. The first area are your local variables and your globals. The local variables live on your stack and globals are in static data segments. Second area, we call the garbage collected heap. All of your objects go here. There's no more multiple zones and specifying a zone when you allocate Objective-C objects. And then there's the malloc zone. Good old malloc-free. It's still there.

So the first thing a garbage collector does is it needs to find out what objects are live in your program. So the first thing it does is it scans your stack. Next thing it does is it goes through all your global variables, finds the pointers that you've stored there. So as I said, the garbage collected heap, that's where your objects go. And there's also a section of that heap reserved for non-objects, some of which are scanned and some of which are not scanned.

So the garbage collector scans your objects and stops with the scanned non-objects, and the unscanned objects are not looked at. Malic zone is explicitly ignored by the garbage collector. So I want to show you a concrete example. Say we have a program that is manipulating work queues. First thing it does is it allocates the first element, stores it on your stack. The object is allocated is in the heap, so this represents a pointer from the stack into the heap.

We allocate another object and a third object. So now we have a full work queue ready to go, and the function returns, stores the head of the work queue in a global variable, gets rid of the stack reference. Now the garbage collector runs. It has scanned your stack and your global variables, and it traces all the pointers it finds until it reaches your data structure, marks it, leaves it alone.

So now we advance from the head of the work queue to another element. We store this new element in another global variable. Erase the pointer from the head. We're going to process that element, and then the garbage collector kicks in. Object disappears. So object management becomes assignment and erasing of pointers. That's all you have to do. So let's bring this now down to how our collector does its job. Pardon me for a second.

When we scan the stack, we look at every word, every pointer-sized word on the stack. Now, we don't look at the entire stack. We look at the live stack in your program. Now, if you have only a single thread running, that means we look at the live range of the current, where that thread happens to be right now. Patrick Beard When we look through it, we look at every, as I said, every word, and we follow the rule, if it looks like a pointer, it is a pointer. We call that conservative stack scanning. We do that because it's fast.

We also do that because we don't have any other choice. The C compiler, the Objective-C compiler that we have does not annotate the stack in any interesting way that lets us scan more exactly. It turns out to not be that big a problem to do that because stacks come and go all the time. And we even provide a facility to clear the stack periodically so stray pointers don't tend to stay there very long.

Next thing, we scan globals precisely. That means we look at every one of the globals you've ever assigned to that might contain a pointer. Unlike the stack, we know exactly which globals contain pointers to objects at any given time. We do that by discovering the globals as you assign to them, and more on how that works in a little bit.

We also scan the instance variables of your objects precisely. So if you happen to have an integer size field that looks like a pointer, we ignore it. And it's your job to make sure your objects are always stored in properly typed variables. That brings me to the next topic.

So I want to talk about three concepts today. These are kinds of references that you should understand. The first one, the primary one, is the strong reference. Strong references are Objective-C object pointers. And they come in various flavors. Most general type for storing an object pointer is the ID type. If you know Objective-C, you know that. Then we have these other concrete class name star pointer types. As long as you store your pointers in variables of these types, the garbage collector will be able to keep track of what you're doing.

So I want to emphasize the way the garbage collector finds your objects is by following strong references. Any object pointer reference from the stack or a global variable will lead to an object or through a chain of object references. That's how your objects stay connected. That's how they stay in touch. That's how they stay alive.

The next topic, the next kind of reference, is the weak reference. As far as I know, we're the only programming language out there that actually has language support for weak references. You've probably heard of weak references. Java has support for them. But as a class, you have to use a wrapper object to represent weak references. The last time I looked, my knowledge might be behind. But that was -- Every time a new release comes out, I check. Do they have language support? We do.

So what is a weak reference? A weak reference is a way to tell the compiler and the garbage collector, "Skip this pointer. I know what I'm doing. I don't want this particular pointer to be traced. I want this pointer to not hold up garbage collection of an object." How do you get one simply by declaring an instance variable or a global variable with a weak storage class? So here's an example, a simple class that has some interface that lets you attach an observer to it. The observer, the observable object, will only send messages about what it's doing as long as the observer is live to the garbage collector. If the garbage collector finds observer objects not reachable, not visible anymore, then it will clear it out. So here's what it looks like.

We have a strong reference to our observer. We destroy that strong reference. Garbage collector clears the weak reference. So the garbage collector does two things. It will not follow the pointer, and if the object is garbage collected, it will clear the pointer. And then, so there are only two states that you can see the weak reference in. Either you read it and you temporarily create a strong reference, or you read it and you see a nil reference. So this can be the basis of caching and is a very useful primitive to have available to you.

So the garbage collector tosses the object, and the observable object only sees nil. The next concept is new for Snow Leopard, and it is called the associative reference. Now, associative references are interesting in that they allow you to create effectively what looks like a strong reference to an object, but without actually storing a pointer.

So a strong reference is a sort of conditional reference. An associative reference is a conditional reference, just like a strong reference is, but there's no storage required. And this gives you some interesting capabilities. For example, imagine you wanted to associate a string object with a color object. With an associative reference, you can do that. Any string, whatever, you don't have any control over the implementation of the string.

In fact, any object instance whatsoever can have an arbitrary other object associated with it. And what this means is if that string object is garbage collected, the color object will be garbage collected alongside it. And as long as the string object is alive, the color object will remain alive. So when we destroy the strong reference to the string, the whole kit and caboodle disappears.

So how do we find out if our object has been garbage collected? You can get an active notification. Your class, your instance can know that it's been garbage collected by implementing a finalized method. This is very similar to Java. The one thing we don't do the same way as Java, we don't allow you to store a pointer to yourself. In a finalized method, we explicitly disallow what's called resurrection.

But the purpose of a finalized method is to release resources, resources that you have allocated in some way that are not managed by the garbage collector. But it's optional. You don't have to write one, and it's avoidable. Oftentimes, a resource you might be managing can be managed better and more simply by using a wrapper object of some sort, something that might be in Foundation. Let's hear some caveats to do with finalization.

As I said, there's no resurrection. Finalized methods get called after weak references are cleared, so even your finalized methods will never see weak references. They're called in an arbitrary order. You can't guarantee that one object gets finalized before another. And they have to be thread-safe, because we are making it so that they might be called On the collector thread, on the main thread, or they might be called on the thread that's currently using an object, or a thread that's currently doing a garbage collection.

The final thing is objects can be messaged after they're finalized because of that arbitrary ordering. All the objects in a cluster of garbage can see each other. And that can be confusing because that means you might get called, some of your methods might get called when you've already finalized some of the state.

That calls for some defensive programming, to say the least. Now, write barriers are something that garbage collectors-- that our garbage collector uses as a foundation for implementing a number of useful features. Weak references, for example, are built upon the concept of a write barrier. We have two kinds of write barriers: strong write barriers and weak write barriers.

What we are able to build on top of the concept of a write barrier are the various garbage collection algorithms. So let me step back and say what is a write barrier? A write barrier is how we do all assignment of object pointers in the language when you assign to an instance variable or a global variable or an indirect pointer, we will issue a write barrier. We don't issue a write barrier when you write to the stack. stack writes are very common, so that's a good optimization.

But this affords us a lot of flexibility by effectively virtualizing the assignment operator whenever it's used on your objects. This allows us to do at least three kinds of garbage collection algorithms that we are working on and have had for a while. Generational GC, there's something called the generational hypothesis. That's an assumption that objects mostly are created for temporary use, and they die very soon after they're created. That's a great example of that is event objects when you're doing event processing.

The other important thing to know about generational garbage collection is that objects are aged, and as they get older, we look at them less often. The write barrier gives us a convenient way to track whether or not objects should be looked at. Another algorithm is a concurrent GC algorithm, as I said. We run the garbage collector in another thread independently of your code, so your code, your program will run with many fewer pauses.

The cost for that, though, is paid for by using the write barrier. It gives us a way to sort of incrementally find out what your program is doing behind the garbage collector's back. The write barrier also lets us do an exciting new technique where we track whether or not objects are known only by a single thread or not. So we call that the thread local collector, and I'll be discussing that in a few minutes.

So to bring this down to concrete terms, a write barrier. The strong write barrier, as an example, if you have an instance variable, whenever it gets written to using a setter method, the compiler generates a call to the Objective-C runtime system. So we get a call to obc assign Ivar for instance variables.

weak references go through a different kind of write barrier. We have the weak write barrier. And we also, in this particular case, have a read barrier. This is how the runtime system guarantees that when you are reading a weak reference, that all you get back is either a valid strong reference or nil. This is a synchronization point with the garbage collector. All right, let's talk about what's new for Snow Leopard. The first topic is how we're making your software more robust. The second two topics have to do with improved performance.

So as I stated earlier, global variables are tracked precisely. We discover the global variables as they go through the global write barrier. We add them to a list of roots of globals that should be scanned from then on. And it works really great, except when it doesn't. In Leopard, We realized that if you pass the address of a global variable down a function call chain, our indirect write bearer had no knowledge of the fact that it was a pointer to a global variable.

So we could miss writes to global variables through that sort of a call path. So here's an example of a workaround for that. Don't ever pass a global to-- address to a global variable and you'll be fine. Use a local variable or an instance variable, either one will work, and then assign it back to the global variable when you're done.

So under Snow Leopard, we've fixed this, and we've added even the ability to know-- we've added to the indirect write barrier, essentially, the ability to know if an address you're writing to is in some global data segment of some library or bundle that maybe has been dynamically loaded. And that also gives us the ability to have a goodbye kiss to the collector if a bundle gets unloaded. So then we won't have any stray references, global references being scanned.

So in Snow Leopard, you'll be able to write code like this, where you simply pass the pointer to the global variable. But if you want your code to continue to run, write it the other way, because then if you want it to run under both Snow Leopard and Leopard. Plus, that way is actually slightly more efficient, because we don't have to classify the pointer.

All right, that was a bug fix. Now this is a new feature. So faster allocation. We studied running Objective-C programs, Cocoa programs, and realized that there's a really big premium on the performance of allocating lots and lots of small objects. Most objects are between 16 and 48 bytes in a 32-bit program.

So if you can make those objects really fast to allocate, programs speed up very, very measurably. So we did this by creating a cache that hangs off of thread local storage and putting the most common sizes in there and periodically refilling it. But it turns out that was not enough to speed up garbage collection because in a sense what we'd be doing is making the garbage collector's job harder by giving threads access to objects even faster. And we already had some problems in keeping up and having the collector reclaim objects as fast as they were being consumed. So that problem was made worse by if we only performed this optimization. But an optimization like this was also added to malloc.

And as you can see, in Snow Leopard, malloc runs six times faster as a result. But it's not enough of an optimization for the garbage collector. Malik's in a different position. It's able to allocate an object off of the thread local cache, and then when someone's done with the object, put it right back on a thread local cache. In our system, the garbage collector is running on another thread. It doesn't have access to other threads, thread local caches.

So we only get half the optimization. So this gave us an idea. What if we could have our garbage collector run on every thread, potentially? And what if we could have objects -- what if we could find out whether objects are known by only one thread or not? The auto-release pool in reference-counted non-GC code works as well as it does because most objects come into existence, are used temporarily, and then they are auto-released all on the same thread.

This gave us the idea of having what we call the thread local collector. As I said, the generational hypothesis is that most objects die young. With the thread local hypothesis, we gained the intuition that most objects stay, live and die their entire existence on a single thread. This gives us an opportunity to run a much simpler garbage collector. That simply examines the current thread stack and all the objects reachable from it. And if we could keep track of which objects were just local to that stack, that collector would only have to consider that set of objects.

And the write barrier, again, comes in and saves us and provides us a way to actually determine, has this object remained local or not? So the write barrier can actually trap a store into a global object and reclassify an object from local to global. We call that an escape.

So Leopard works really well. It comes and picks up your garbage. It's kind of slow. With Snow Leopard, performance is going to go way up. And here's a preliminary graph of what kind of performance we've been seeing on some specialized benchmarks. We call this the recycling rate. This is the rate at which an object can be allocated and then reclaimed. And some of our measurements indicate that we can get objects in and out of the thread local cache a factor of 30 times faster than we were doing before. This is going to be huge.

So if you've-- Thank you. And thank you to Blaine Garst and Josh Benke for working so hard on it. If you had the excuse of performance, "Ah, garbage collection is too slow," we hope to prove you wrong and hope you'll prove us right. So now let's get into some nuts and bolts using garbage collection. If you haven't done it before, this is how you do it. You turn it on, you opt in to garbage collection, you go into Xcode, you make a new project, and if you're just writing an app from scratch, just turn it on.

Type in "garbage collection" in the search box in the Preferences Project Inspector and choose "Required." Required is the recommended choice for applications. Supported allows you to write a framework that can actually run in either garbage collected mode or non-garbage collected mode. In my demo, I'm going to show you an example of such a framework.

So here's the hello world of garbage collecting programs. If you've turned everything on correctly, one checkbox. Then this program will print "Hello, Garbage Collector" because the NSGarbageCollector class is the Foundation interface to the garbage collector, returns nil if the garbage collector mode is not turned on. So now I'm going to talk about a few design patterns that garbage collection influences, garbage collection affects.

First one is the venerable accessor method pattern. Set get methods. Everybody does them. Nobody likes them. But they are a fact of life. When you write one using retain-release, you have to follow something that looks roughly like this pattern. This is the recommended pattern we all follow. You have to make sure that when you are changing a value that the value is, in fact, a new value, then it's safe to call release on the old value and call retain on the new. The getter method uses the auto-release pattern, retain auto-release. That guarantees that the object will stay live with respect to the current thread's auto-release pool.

When you write it in garbage collection, if you've written any Java code, this is how you write it in Java. Just get set. All that ownership, transfer of ownership logic that we had to do before is now nicely tucked away in the runtime system behind being done by the write barriers.

Now for extra credit, not so much extra credit these days with so many cores around and needing to write lots and lots of threads in our programs. To write your accessor methods thread safe, you've got to use some sort of critical section. Wrap the code that we did before in the critical section. Same basic idea, but now this is the thread-safe version. Well, guess what? Under Garbage Collection, you're done.

Another thing that is very problematic in reference-counted code, retain-release, is the cycle. The cycle is a bugaboo. You can't handle cycles cleanly in reference-counted code. This is why our frameworks take such great pains to use what are called non-retained references and to advertise. You have to read the doc.

You have to know, "When I put this object there, I better worry about taking it out when I'm done." So why? Because here's an example of a cycle. We have a pointer that's pointing to one of the elements of the cycle of this circularly linked list. And that object has retained count of two. We get rid of it. Its retained count goes to one. Now the whole thing is a leak.

Under garbage collection, objects have a retain count, but garbage collected objects, the retain count is zero. We have this retain count as a backward compatible way of interacting with core Foundation objects, but Cocoa objects don't use it. They don't even allocate any space for it other than a couple of bits.

However, you can use that retain count if you need to. You can call cf.retain on a Cocoa object. You do that if you're going to store that pointer. Remember I said the garbage collector doesn't look in the malloc zone. But if you have some malloc data structures and you just need to put that object there and hold on to it, you can call cf.retain on it.

When you get rid of that, though, that object's retain count will go to zero, and garbage collector tosses everything in mass. No problem. Okay, the next thing I want to talk about is nib loading. So nibs are these files. They contain user interfaces. We all know them. We all love them. They work a little bit differently under garbage collected code. So here's a nib that has one top-level object in it. It's a HUD panel.

Under retain release, I have a simple program that has a button, test. When you click that button, the window pops up. It just loaded that nib. Do it again, another one comes up. Third time. We get three and we see that really nice alpha blended effect. Ooh. OK. Under Garbage Collection, run the same program. We recompiled it.

Wait a second, where did that window go? Do it again, third time, The window comes up and it goes away. Window comes up, it goes away. What's happening? Under garbage, under retain release code, top level objects by default leak. They come up, they have a retain count of one, nobody's holding onto them. They stay around.

Under GC, they go away. So if you're creating objects whose sole side effect is to set something up, set some preferences, do whatever, And they would leak by default in reference-counted code. The GC collects them. So you have to be aware of that, but mostly just worry about connecting your objects with outlets. I had one particular case where I needed to create some objects that wrap some streams, and the only way I could keep them live was by storing my object self into a global variable.

I had to do that under GC to keep it rooted. Another application of garbage collection, now this gets back into the weak references system, is called weak caching. So say we have an application that deals in lots and lots of images. It could be a screen saver bouncing images around and it's displaying them at various scale sizes or something where the performance of rendering each frame is critical. So we don't want to let the graphic system scale the images, we want to pre-scale the images.

So we have a set of scaled images that get created one by one and held onto. But eventually, if we run through lots and lots of scale sizes with lots and lots of images, we might run out of memory. How do we get rid of them? How do we know to get rid of them? Well, the weak reference system can give us a handy way to do that.

Here's a class called an Image Scaler, and it has two instance variables, an image that we want to get various scaled copies of, And a map table that will act as our cache. So it's real simple. We create one with an image, and we call the scaled image method specifying a size, an NS size.

So this method creates the map table using a special method, Map Table with Strong to Weak Objects. Now, in case maybe you're not aware of this, but NSMapTable used to be a C-based API from the olden days. And in Leopard, we enhanced it. We gave it a lot more power. We turned it into an object for one thing. We also made it a sort of dictionary Swiss Army knife.

You can configure these things in so many ways, I don't even understand all the combinations. But this one is particularly useful. Strong to Weak Objects. The strong refers to the keys that we're going to use in the dictionary and the map table. And weak refers to the values that we want to hold onto, in this case, the scaled images.

So when the scaled image method is called, we take that size that was specified that we're asking for, we wrap it in an NS value, and that will be our key. We then check to see if the cache contains that copy of it. If not, then we make a new copy, we scale that image, and store it in our cache.

Now, what's great about this, for as many clients as happen to be using this image, this scaled image, at the same time, think threads or multiple calls to it, These images, these scaled copies, will all be shared, and then when all the threads that are done with those images go away and release those images, that copy will go away. So the cache does this for us for free.

So let's talk about finalization a little bit more in depth now. Finalization is something

[Transcript missing]

For all the reasons I said before, the caveats that were stated, it's tricky. You've got to make sure your finalizers are thread safe. So it's a better idea to look at your objects, design your classes with states in mind, the allowed states that the object should go through. So think of it as a state machine. When an object is done, prefer an explicit shutdown. A great example of this is a file or a network connection, something that is holding onto resources that are fairly costly. You should just design that right into your API.

So finalization is there primarily as a backstop. One very great advantage of a garbage collected system over a non-garbage collected system is in the face of exceptions. We don't have fancy stack destructors where objects will be torn down as the stack unwinds. We do have an exception system that is compatible with that.

We actually don't need it under garbage collected code because the finalizers of the objects that might have been allocated along the way while you were throwing-- before you threw the exception, will get invoked. So the finalizers are there to sort of clean up, make sure things aren't left dangling, resources are not clogging up the system. That's a great use of a finalizer.

So, concrete example, some sort of simulation. You've got an object that goes into a mode. It is running its engine. Maybe it's doing a physics simulation or it's doing an animation. Maybe there's a thread or a timer behind it. Make sure that that object has an API to tear it down gracefully.

Please don't leave the motor running. So how do I get rid of a finalize? Here's a case where we have a class that holds onto a buffer that's been malloc'd. And in this case, it's technically correct. We need a finalize method. If we don't have one, that buffer, it's going to leak.

But we can change this. There's a Foundation alternative to it. It's called NSMutableData. The NSMutableData actually is even better than a malloc-free because it's a resizable buffer, a resizable block of memory. This is all very simple stuff. But if you just simply switch from that to the other, your finalized method goes to nothing.

In fact, you don't even need one. There are a number of systems, subsystems in Cocoa and things you can use. And this is just a short list of examples. These are the kinds of things that really require you to disconnect them. You can't just simply, in most cases, leave them to the garbage collector to clean up.

You bring up a window. Well, except for that case I showed you with the nibs, panels will disappear if they're garbage collected. But windows do not. Windows are more special. They get attached to the user interface of your program. So the user will close a window. That's a very active operation.

Timers, on the other hand, well, they're not visible. Timers have to be torn down, just like in reference-counted code. So these are the kinds of things that you will still have to think about. Garbage collection is a very important part of your design. Garbage collection won't solve all these problems for you.

Key value observation is another one. If you happen to create an observer on an object, don't let the object that's being observed garbage collect while the key value observation is in force. Most of the time you're not going to have to think about this if you're using bindings. The binding system takes care of it.

The last one is the notification center. The notification center uses weak references. So, you don't have to write a finalized method if what you--all you need to do is unregister your object from, uh, the notification center. However, you do want to make sure you don't leave your object in a bad state and still attach to the notification center. So, there's a case where maybe as part of your object's explicit shutdown, you should take it out of the notification center. But you don't have to. It will be removed for you.

I don't know if you've seen this little guy. That's the logo for the mascot of GDB. Fish, I can't remember the name of it, it's a kind of fish that lives in shallow water and squirts and eats low-hanging bugs. Just thought that was interesting. We've added support to GDB for doing real low-level tasks having to do with garbage collection.

So one of the facilities is you can now, within GDB, if a program has crashed, usually that's why you're in GDB, you can look at the total history of an object's allocation. That is, all of the stack logs, all the stack crawls of an object, when it was allocated and deallocated.

This facility is invaluable when debugging garbage collection problems. If you forgot to create a strong reference, you used a void star to hold onto a pointer to a garbage collected object, and it goes away, you can use this facility to find out who last allocated it and when did it get deallocated.

Another facility is you want to know, well, why is this object still here? It should be gone. You can ask GDB, there's a command to ask it, what are all the objects currently referencing this object directly? And there's also a way to find out what global variables and along what path is my object being referenced? We call that root tracing. So that's in GDB.

The next tool we provide, the next level up the chain, a hierarchy of high levelness, is the GC instrument in the Instruments program you've probably heard about. The GC instrument is a sort of a version of the object alloc tool with Knowledge, customized knowledge for the garbage collector. It can also show you the same information. It can show you What objects are referencing your objects' direct chains look like, and you can look at-- peruse the stack histories. It's a good tool to try to understand your program.

And furthermore, it can actually show you What are all the objects currently in your program? You can search for them by type, search for them by pointer. So it's a great visualization tool, and I'm going to be demonstrating that in a few minutes. Finally, there's this cool little open source tool called Fscript.

And it is really handy to look at your program while it's running, interact with it, and sort of do what-if type queries. You know, like, well, what if I got rid of this pointer right here, right now? What would happen? So that's a nifty little tool. It's now garbage collection compatible, and it's packaged as a framework. And it is a framework that works in both GC and non-GC. So it's a good example of that if you're interested in doing that. So let's give this a whirl. So I have instruments set up right now to run a demo application.

One of the things we can do is pause it and take a look at-- How big our heap size is, how many objects are around in terms of overall memory size, And the top bar in this upper display is the amount of virtual memory set aside for the program, whereas the other, the tiny one, is how much is actually in use. It's a tiny little program.

Unpause. So this is a tiny little application. It's very similar to the nib loader that I showed you before. It has two buttons, one that creates a panel, one that creates a window. The keep checkbox says, should we hold a reference to the object after we allocate it? So if I make one, Move it around, make another one. First one, garbage collects. Goes away. Do it again just to prove that it wasn't a fluke. Second one goes away. Uncheck the checkbox. Goes away. Great. That's all that's going to plan. Now, we create an NSWindow.

Create another Ennis window. Another Ennis window. None of the objects are garbage collecting. What's going on? Oh, I know. It's my checkbox. Let me uncheck it. Go away, please. Go away, go away, go away, go away. They're not going away. Why aren't they going away? So let me simplify it.

Well, I happen to know that-- let me get rid of that one, make another one. To show that this object is actually still referenced by my program, I want to pop up an F script window. In F script window, I have this object C, which is my controller. And its window field right now is null, and yet the object's still staying around.

A window, not a HUD. There. Now look at it again. All right. So this object is the thing that's holding on to my window. F script lets me look into that. I could do C window. I could do C set window. No. Still, the object's not going away. All right, I know it was this address, so let's pop into instruments and see what's going on. First thing I have to do is take a snapshot.

You can set it to periodically snapshot. I'm just having it snapshot on demand right now. Now, I can have it show me all the objects in the heap currently, lots and lots of strings. And I can paste in Copy. Paste in the pointer. All right. There's the NSWindow.

So we have this block list. We have this one object that's found in it. There's a detail view over here that gives me some information about the object. Here is the stack crawl of when the object was allocated. Makes sense. I recognize that code. That's my code. PCB controller, blah, blah, blah. The other thing it can tell us over here is what's holding on to this window. Huh, it's telling me that the NSApplication object is somehow holding on to the window. I can pop back up to F script and say NSApp.

In fact, there are two windows, but I don't really know which window is which, so I want to figure that out. So I can ask it using this handy send a message to all the elements of an array. That's really handy. I wish GDB had that. This basically lets me easily positionally identify the windows that I'm interested in.

So what the heck? Why is the application still holding on to it? I happen to know that the NS app is supposed to only have weak references to windows. So why is it staying around? Well, we can dive into this object if we go back to instruments, and it can tell us Exactly how the object is connected. This display over here gives me a path. From the NS application object all the way to the NS window.

So it tells me, oh, it's connected to the window menu. There it is. Bring it back up. So it's still alive because of that. If I close the window, it disappears. Windows take care of their own lifetime. So Instruments was able to tell me it's basically communicating with my process. It's able to enumerate all of the objects in the system, and it's able to find out how they're connected together.

All right. Demo, demo. So we have one more session where we're going to be talking about advanced topics in garbage collection. If you're interested in learning more and more about that, we talk about how core Foundation interacts, how to do dual-mode frameworks, and porting. Maybe you want to port a large body of code.

And then some more about some of the lower-level tool support. So in summary, Garbage collection is like having your own personal accountant. He's there at your side. He's doing your bookkeeping. He's balancing your checkbook. He's making sure you deliver your project on time. You don't have to worry about bookkeeping.

It's also checking to make sure the amount of memory you're using is staying under control, so you're going to be under budget. And finally, in Snow Leopard, with a thread local collector, you have effectively a team of accountants all working on your behalf and at your service. There's another session tomorrow, as I said. Greg Parker's going to be giving a talk, and we already had a session yesterday. Thank you very much.