Monday, February 12, 2007

Memory Management: C vs. Java

Like many other companies, the company I work for decided to move from C to Java. There were a lot of good reasons for the switch. One of the biggest reasons was that we could ditch manual memory management (malloc(), free(), etc.) for automatic memory management (garbage collection).

Garbage collection is usually marketed as having the following advantages:

  • No memory leaks
  • Less development time spent on memory management

Let's examine these claims in more detail.

No memory leaks?

It's not really entirely true that garbage collected languages have no memory leaks, depending on your exact definition for "memory leak". Here are a few ways you can still leak memory in garbage collected languages like Java:

  • Accidentally keeping object references in collections.

    Garbage collected languages induce a false sense of security in many developers. I've seen code that leaks memory by the megabyte because of developers forgetting to remove object references from collections when they're done with those objects.

  • Forgetting to release non-memory resources which themselves have allocated memory "under the covers".

    Many APIs, such as AWT, Swing, and JDBC are partially implemented in native code. That native code often allocates memory from the operating system. If the application fails to release one of these kinds of resources, memory is leaked more often than not.

It's worth pointing out that I'm not suggesting garbage collected languages are just as likely as non-garbage collected languages to leak memory. I'm just trying to show that garbage collected languages can also leak memory.

Less development time spent on memory management?

There's no doubt that it takes more time to write software that does manual memory management. After all, those developers have to take the time to think about when memory resources can be safely disposed.

There's also no doubt that developers will likely spend less time fixing memory leaks in garbage collected programs. That's because there should be less memory leaks to track down and fix in the first place.

However, there's another issue that's often swept under the rug...

Before switching to Java, the company I work for used to sell products written mostly in C. Not surprisingly, these products had the occasional memory leak. It usually caused quite a stir around the office. One or more developers would spend anywhere from a few hours to several days hunting down and fixing the leak. Manual memory management was wasting our time! Garbage collection would free us from this onerous task!

Fast forward to the present. Hardly a day goes by that I don't hear about our JVMs running out of memory, or our products not scaling well because they consume such a massive amount of memory. It seems like developers are constantly trying to determine where the memory is going and how to use it more efficiently.

All of a sudden, the occasional memory leak doesn't sound so bad. Personally, I'm quite convinced we have more memory problems now than we did before.

Conclusion

To be fair, I can't say with any certainty that massive memory consumption is a common issue in garbage collected languages in general, though it does seem to be a problem with Java in particular. The company I work for has a lot of really smart architects: too smart, if you know what I mean. They're ready and eager to deploy complicated patterns and over-engineered solutions for every problem, which most of us mere mortal developers find really hard and time consuming to maintain.

Apparently, someone forgot to tell them that more time is spent on maintenance than on new development. Writing easily maintainable code should always be priority #1. Using every pattern imaginable isn't nearly as important.

But I can say with certainty that we seem to be spending inordinate amounts of time worrying about the shocking memory requirements of our applications these days. It seems garbage collection isn't quite the panacea that we were sold.

5 comments:

Unknown said...

You make some really good points in this post. I couldn't agree more about maintainable code being super important.

I would be interested in an overall post from you on the differences in development/support time in C vs Java or C++ vs Java. I am of the opinion that almost always going OO is a drag on development time and that this is especially true if the developers are very bright. My logic is that people like to be entertained and they will entertain themselves while coding. If you give them a language with a lot of bells and whistles, they will ring every bell and blow each whistle. Bright people find ways to make the bell sound like an oboe (carrying on the "bell" analogy) which can be cool but is usually unsupportable.

Rick Kimmel said...

Adam, it's been my experience (which may be biased) that OO design takes longer up front but the maintenance costs are much lower. I don't have any real numbers on that -- I'm just going on gut feel. What's unfortunate is that some management doesn't like it when people take longer to code it -- even when it makes it more maintainable -- so many developers are discouraged from doing it. Where I work that trend is changing. We're encouraged to do test driven development and do quality design (and refactoring if necessary). We just need to account for it on our scrum backlog when we make estimates.

I don't necessarily agree with the bells and whistles. I don't see a lot of that around here but most of us are senior developers who have been around a while. I would expect to see that kind of thing with younger "hot shot" programmers who haven't learned the wisdom yet.

Unknown said...

Rick,

The "longer to design, easier to maintain" has been the general wisdom about OO. I don't find it so. I find OO takes longer to design (if you do it right) a bit less time to code (if you leverage good libraries, which seem more abundant with OO languages) and MUCH longer to maintain. What ends up common is over complex inheritance and bizarre OO language rules (see C++ and "do we do virtual with this method"). Base classes change and those changes ripple through out the codebase. Frequently the people on maintenance are not your top coders, since those people like to do development and everyone likes to keep top coders happy, so the design which was 'so cool' ends up choking on its own complexity.

Perhaps the company you work for has figured out how to get people who are experienced and bright without being primadonna's. I would be interested in hearing more about the hiring practices they use and the development environment they have.

Rick Kimmel said...

I can't speak for the hiring process since I'm not involved with that. About all I can say is that the people responsible for hiring are pretty good at what they do. The ratio of good/bad hires here is unusually good.

We have a very professional environment here. Not really sure how else to describe it. All developers are senior level and most of us are in our 30's and 40's and we don't seem to have anyone with personal agendas. We're all team players. That sounds a little cliche but here it's true.

Ed Jensen said...

Adam,

I couldn't agree more re: languages with lots of features. Developers love features, whether or not the features are good for them.

There's a phrase I use to describe it: Shiny Object Syndrome. I plan to blog about it eventually. (But don't count on it. The heat death of the universe may happen first.)

C++ is a good example of Shiny Object Syndrome taken to an extreme. It has largely resulted in the demise of C++ in quite a few application domains.

I've heard some C++ programmers claim that you can merely use a comfortable subset of the language. I consider it a ridiculous suggestion since most programming isn't done in a vacuum, and you have very little control over what languages features your colleagues end up using (and abusing).