I regret writing this article. See my explanation.

Garbage Collection is Wrong

The title of this article may scare you - I'm not saying GC is bad, I'm saying that GC is the wrong choice to make in most cases.

Garbage collection is wrong, or at the very least, inadequate and overbearing. RAII is the way to go. Don't believe me? Then don't skim-read.

In computing in general, any computing environment you will work in will have multiple kinds of resources which can be acquired and released. Who acquires and releases resources? Programs do. How do they do it? It depends on the programming language. But what exactly is a resource?

Resources can be, but are not limited to being:

Now, you may categorize and subcategorize those as you wish, but they are all examples of resources. They key is that programs actively request access to a resource and then later should release that resource. How you acquire a resource and how you release a resource depends on the resource, of course. The trouble comes when a program "forgets" to release a resource when it is done with it. This results in a resource leak - at least until the program ends, when nearly all modern environments release resources that were still in use at the program's termination.

But many programs don't end any time soon, and when they "forget" to release a resource, you end up with a resource leak. Unfortunately, since the first kind of resource people think of when listing them off is memory, the term "memory leak" is more common than the term "resource leak". This is where garbage collection comes in.

Someone thought "I know how to solve memory leaks! Obviously the programmers being accepted into the industry have not been taught how to properly manage memory, so we'll have the programming language do it for them!" Great! Excellent! Now by simply having the computer decide when you're done using memory, we don't have to worry about forgetting to release memory we acquired. But then garbage collection was actually implemented by a variety of programming languages.

In a majority of GC languages, garbage collection is not optional. It's not just an add-on, not just a language extension, not just a feature that can be turned off. No, it is an integral part of the language and cannot be ignored. So how do you explicitly release memory? You don't. Not because some group agrees you're not supposed to, but because you actually cannot within the bounds of the language. You may only "allow" memory to be garbage collected, by forcibly making sure no part of your code is able to access that memory anymore. Then, when the garbage collector "feels like it", it will release memory that cannot be accessed. How and when the garbage collector runs depends on the implementation, which can vary even in the same language. Hooray for modularity! Oh wait, why is there a hole in my pocket?

That's right, there's a cost. Multiple costs. For one, now code has to be analyzed at run time to determine what memory is still being used and what memory can be released. This could happen any time for any amount of time, and the problem is hit on the head when you talk about multiple threads of execution. In most GC languages, there are no "memory boundaries" between threads, so when the garbage collector runs, all threads of execution are paused - at least, in a majority of in-use implementations. Speaking of a majority of in-use implementations, most don't run the garbage collector until the program runs out of memory. This means that most GC programs will 1. continue to use more and more memory and 2. randomly freeze while memory is analyzed and released.

But this is all common complaints that get batted down by GC enthusiasts. I save the best for last: garbage collectors only deal with memory. They do absolutely nothing about every other kind of resource. Ever wondered why you had to close that program to use that file again? The programmer thought GC would take are of it.

The programmer was at least somewhat right - GC would eventually take care of it, when the memory associated with the file was cleaned up and the file handle closed as a result (think of Java's finalize method). While GC works (to a debatable amount) for memory, it does not clean up other active resources within a timely fashion.

What problem were we originally trying to solve?

Object *obj = new Object[size];
//...code...
delete[] obj; //oops! Easy to forget

What other problem did we not solve?

myfile.open(filename);
//...code...
myfile.close(); //oops! Easy to forget

To not see the similarities is absurd. In both cases, we acquire a resource, act on that resource, and then we're supposed to release that resource. Memory is just one kind of resource, and unfortunately is is the only kind of resource that garbage collection manages. So what have GC languages done to deal with their fundamental flaws? Why, they've come full circle:

//Java 7: try-with-resources block
try(InputStream fis = new FileInputStream(filename)) {
  //...code...
} //implicit fis.close()

//Python: with-as block
with open(filename, 'r') as f:
  //...code...
//f.closed == true

So what's wrong here? Well, we've come back to square one: you still have to be educated to use these forms instead of the more direct forms. The only added benefit is that the resource is released no matter what path the code takes (exception, early return, break from a loop, etc). This is starting to sound very familiar to a certain something...hm...what could it be...

Introducing RAII: Resource Acquisition Is Initialization

Bjarne Stroustrup, the creator of C++, discovered RAII and is a strong advocate for it. Funny, C++ seems to have lots of things other languages don't - const correctness, destructors, and now RAII. Know what else is funny? In modern C++, using new or delete in your code is wrong. It's not done. Nobody writes code like that anymore in C++. That also means nobody ever forgets to release a resource in C++. Why not? Because of RAII.

I would not say RAII is a design practice - rather, it is a side-effect of having a language with both destructors and variables of automatic storage duration. For those of you who have no idea what I am talking about, think: when was the last time you ever had to explicitly release an int? A double? A boolean? You never had to, because in just about every programming language in use today, primitive types have automatic storage duration - they exist as long as they are in scope.

Scope...scope...scope...that sounds familiar, right? Right! Everything in scope is accessible by the code, and everything out of scope is inaccessible to the program code. But wait - weren't we just trying to determine what was and was not accessible to the code when we were implementing garbage collection? Why was that so much more complicated? Why indeed!

In C++, we rarely use pointers. Pointers in modern C++ have very few valid use cases, so you hardly see them anymore. How do we handle dynamically allocated memory then? We use the smart pointer wrapper classes, such as std::unique_ptr, std::shared_ptr, std::weak_ptr, etc. thus associating memory with scope. When automatic storage duration objects go out of scope, their destructor is called, and the destructor releases any memory associated with the object it is destructing. They key is that the destructor is called immediately when the variable goes out of scope, not "when the garbage collector feels like it".

So how are all resources in C++, including memory and files, dealt with?

ResourceType resource;

Done! That's it! On that line we acquire the resource (possibly with arguments to the constructor) and then never worry about it again. When the variable goes out of scope, the destructor is called and the resource is released. Due to this, almost all destructors in C++ are given the default implementation by the compiler, since no special cleanup code needs to happen. No more calling new or open, no more remembering/forgetting to call delete or close, just acquiring and using resources and letting them fall out of scope.

RAII is simple, elegant, and even optional for those who want to "do it their own way". Compare and contrast with garbage collection, and the result is you either agree or disagree with my stance. I like to keep an open mind, and am able to admit that I am wrong when I am wrong, so if you think RAII is not the best thing in the world like I do, feel free to explain exactly why you think your alternative is better. I'm having a hard time imagining how RAII isn't the best, however, so I would love to see what creative way you outperform RAII.