Another post from Andrew Stellman, coauthor of Head First PMP and Head First C#.
Back in November, there was a really interesting Slashot post about some C# trouble that the Princeton team working on the DARPA Grand Challenge ran into. As an alum of the Carnegie Mellon School of Computer Science, the DARPA Grand Challenge is near and dear to my heart. Here's a little-known fact: when I at CMU, I played bass in a band at the time with one of the grad students working on the autonomous vehicle project—that's the project that eventually led to the CMU Tartan racing team that won the 2007 DARPA Urban Challenge. My band-mate on the project played guitar, and kind of looked a little like Pete Townshend. At the time, the project was built on a Humvee. It was a pretty impressive vehicle. It was huge, crammed with Sun workstations, covered in distance sensors and video cameras, and had a big, imposing laser scanner mounted above the windshield. In the mornings, they had it drive itself around Schenley Park, and he had a good story about a jogger who freaked out and had a panic attack upon seeing this truck rolling around without a driver.
Anyway, I wrote up this response to that Slashdot post, but I never really found a good place to post it—it's a little off-topic for our Building Better Software blog, which doesn't really delve into technical concepts. So when the Head First Labs folks asked me and Jenny to do some guest blogging, I thought it would be a really good way to show off the style that you'll see in Head First C#. So I'll see if I can shed a little light on exactly what kind of problems the Princeton DARPA team ran into, how they could fix it using a clever C# construction, and hopefully give you a little taste of the kind of visual explanation that you'll see throughout Head First C#.
The Slashdot article is about a blog post by Bryan Cattle, a member of the Princeton DARPA Grand Challenge team. (Go Tartans!) Here's how he describes the problem:
We had vacations coming up a few weeks after the race, so we left the cars in Vegas and returned, two weeks later, to investigate the problem. One of our team members downloaded the 14-day trial of ANTS Profiler and we ran it on our car's guidance code. We profiled the memory usage and saw the obstacle list blowing up. How could this be? We called "delete" on those old obstacles! To our amazement, it was only minutes before we realized that our list of detected obstacles was never getting garbage collected. Though we thought we had cleared all references to old entries in the list, because the objects were still registered as subscribers to an event, they were never getting deleted.
And here's how he resolved it:
We added one line of code to remove the event subscription and, over the next three days, we successfully ran the car for 300 miles through the Mojave desert.
So what happened, exactly?
I'm not 100% positive, but I've got a pretty good idea of what I think happened. Let's say we've got a class called EventSubscriber. Let's create an instance of the object:
EventSubscriber subscriber = new EventSubscriber();
Here's a picture of what the heap looks like after that statement runs. We use pictures like this throughout Head First C# to illustrate what's going on behind the scenes. The grey blob represents the heap, the round circle inside the blob is an EventSubscriber object that's living on the heap:

In Head First C#, we put a lot of thought into how we could visually represent references. This wasn't easy, because references are a pretty abstract concept, and don't have an obvious visual. But it was really critical to get it right, because a lot of people learning C# have trouble grasping the concept. I really felt that it would be a concept they'd get easily if we just chose the right metaphor. We finally came up with a visual metaphor that really clicked for us: a label from a label maker. So we'd visualize that line of code by creating an object (the circle) on the heap (the big grey blob behind it) with a label on it. That metaphor really worked well, and we reused it throughout the book.
Now let's take away the reference, like the Princeton team thought they were doing:
subscriber = null;
What you'd expect to happen is that since there are no more references to the object, it should be marked for garbage collected and eventually removed from the heap. Here's how we represented that visually:

And that's how we visualize an object disappearing from the heap. Unfortunately for the Princeton team, the picture gets a little more complicated when the object subscribes to an event—in this case, let's say it's an event that's raised by the form:

Even if the subscriber reference is no longer pointing to the object, it's still subscribed to the event. And that means that there's a delegate pointing to a method inside the EventSubscriber object... which means there's still a reference keeping it alive. (We explain all of this in a lot more detail in chapter 11 of Head First C#.)
The rest of this post is about reproducing the problem. And it's actaully pretty easy to reproduce. You can do it yourself in just a few lines of C#. Here's how. (Any time you see a "Do this!" arrow in Head First C#, it means we're giving you a set of steps to follow.)
If you're a C# programmer, you shouldn't have any trouble following this. But if you're a Java programmer, I want to call your attention to the using and IDisposable construction—it's one of my favorite parts of C#. IDisposable is an interface that's really similar to Closeable in Java, but it's coupled with a nifty keyword, using. You can see how it works in the code below.
Create a new Windows Forms Application project. We won't use any new C# 3.0 features, so this should work just fine in Visual Studio 2005. (Here's the project code for this example—it's a Visual Studio 2008 project.)
- Build this simple form with four buttons (named createObject, fireEvent, createWithUsing and collect):

Add an event to your form (and you'll need an int field called number):
public event EventHandler SomethingHappened;
private int number = 0;
Add an EventSubscriber class to your project
Now add a class to your project to subscribe to that event:
using System.Windows.Forms;
public class EventSubscriber
{
private Form1 form;
private int number;
public EventSubscriber(Form1 form, int number)
{
this.form = form;
this.number = number;
form.SomethingHappened += form_SomethingHappened;
}
void form_SomethingHappened(object sender, EventArgs e)
{
MessageBox.Show("Something happened!", number.ToString());
}
}
So look over what we've got so far. When your form creates an instance of EventSubscriber, that new object will subscribe its form_SomethingHappened() method to the form's SomethingHappened event. When the form instantiates it, it passes an ID number to the constructor—it pops up a message box with its ID in the title bar whenever the form's SomethingHappened event is fired.
-
We'll want to know when the object gets garbage collected, so add a finalizer to the class. If you haven't used one before, a finalizer is a method that gets run just before your object is garbage collected. Here's what it should look like:
~EventSubscriber()
{
MessageBox.Show("I've been collected!", number.ToString());
}
-
Okay, if you've got the EventSubscriber class in your code (including the finalizer) and it compiles, you're in good shape. It's time to reproduce the bug. Here's the code for the createObject and fireEvent buttons in the form. They call a method in the form called OnSomethingHappened()—that's a pretty standard way to invoke events. All it does is fire off a SomethingHappened event:
public void OnSomethingHappened(EventArgs e)
{
SomethingHappened(this, e);
}
private void createObject_Click(object sender, EventArgs e)
{
EventSubscriber subscriber = new EventSubscriber(this, number++);
OnSomethingHappened(null);
}
private void fireEvent_Click(object sender, EventArgs e)
{
OnSomethingHappened(null);
}
Now you can see exactly what went wrong. Press the "Create an EventSubscriber" button. It does what you'd expect it to do—it creates a new instance of EventSubscriber, passing a reference to itself into its constructor. The EventSubscriber object subscribes to the form's SomethingHappened event. And then the form calls its OnSomethingHappened() method to fire its SomethingHappened event. That calls the EventSubscriber obect's event handler, the form_SomethingHappened() method, which pops up a message box.
But wait a minute... wasn't the finalizer supposed to run when the object got garbage collected? After all, there aren't any more references to the object. So it should disappear, right? So let's be sure. Click the "Fire the event" button. Hey! The object is still around. It turns out that it's not gone after all. Now close the program. The objects' finalizers get run—the objects were still around, right up until the program was closed! And that's the problem that the Princeton DARPA team ran into.
So what should we do about it?
Use IDisposable and using to avoid the problem
This is a really good place to use a very helpful feature of C#: using and IDisposable. We spend a lot of time talking about them in Head First C#, but here's the basic idea. IDisposable is a really simple interface that only has one member: a method called Dispose() that takes no parameters and has no return value. If you've got a class that implements IDisposable, then you can declare it with a using statement like this:
using (MyClass referenceVariable = new MyClass())
{
// Code to use the new instance of MyClass
}
When you do that, referenceVariable is only valid inside the curly brackets. And as soon as the program is no longer executing that block of code, it calls the object's Dispose() method. (Under the hood, C# is using a try/finally block to make sure Dispose() runs.)
Take a minute to think about this, because it's a really unique feature of C#—it's actually one of my favorite parts of the language. It closely ties an interface (IDisposable) to a C# keyword (using) to give you a way to avoid some of the trickiest and difficult-to-find bugs.
And as it turns out, IDisposable and using give us a really easy way to eliminate the problem that's keeping our objects around long after we're done with them. All we need to do is make the EventSubscriber class implement the IDisposable interface and add a Dispose() method to the class to unsubscribe from the form's event. Here's what that should look like:
public class EventSubscriber : IDisposable
{
public void Dispose()
{
form.SomethingHappened -= form_SomethingHappened;
MessageBox.Show("I've been disposed!", number.ToString());
}
// The rest of the class is the same
Once that's done, you can add code to the third button to instantiate EventSubscriber inside a using statement:
private void createWithUsing_Click(object sender, EventArgs e)
{
using (EventSubscriber subscriber = new EventSubscriber(this, number++))
{
OnSomethingHappened(null);
}
}
There's one more thing to add. The garbage collector doesn't run all the time. It watches your application, and figures out the most efficient way to run. And it does a really good job of it—in general, much better than you could do yourself. But sometimes—very rarely, and only under very specific circumstances—you do need to tell the CLR to collect the garbage. And that's what the static GC.Collect() method is for. So make the fourth button run the garbage collector:
private void collect_Click(object sender, EventArgs e)
{
GC.Collect();
}
Now run the program and press the third button to create the object with a using statement. When the form fires its SomethingHappened event, the object responds just fine. But then it pops up a message box telling you that its Dispose() method's been called. Now try firing the event again, using the second button. Nothing happens! The object is no longer subscribed to the event. If you wait for a few minutes, the program will pop up one last message box telling you the object's been garbage collected. But if you click the last button on the form, you can tell the CLR to collect any objects that no longer have any references keeping them alive. And when you do, the object's finalizer will finally run!
So what's the moral of the story? A lot of times you'll end up writing an object that needs to do something to clean itself up when it's done. Sometimes it needs to release resources, like closing a stream. Other times, it needs to unhook itself from an event or delegate. And when you've got a class that needs to clean up after itself, then the best way to do that is to have it implement IDisposable and always use a using statement when you want to instantiate it. If the Princeton team did that, well, my alma mater CMU would probably have kicked their butts anyway. Go Tartans!







By 










Leave a comment