+8  A: 

if I have an app written in native C++ requiring 100 MB of memory, to achieve the same performance with a "managed" (i.e. garbage collector based) language (e.g. Java, C#), the app should require 5*100 MB = 500 MB? (And with 2*100 MB = 200 MB, the managed app would run 70% slower than the native app?)

Only if the app is bottlenecked on allocating and deallocating memory. Note that the paper talks exclusively about the performance of the garbage collector itself.

Michael Borgwardt
For context, most of the large realtime apps I've worked on spent about 10-15% of their time on managing memory when relying on the OS or standard runtime's allocators. I've seen that number fall to about 5% when using fixed heaps, block allocators, a variety of tough optimizations.
Crashworks
+2  A: 

Michael Borgwardt is kind of right about if the application is bottlenecked on allocating memory. This is according to Amdahl's law.

However, I have used C++, Java, and VB .NET. In C++ there are powerful techniques available that allocate memory on the stack instead of the heap. Stack allocation is easily a hundreds of times faster than heap allocation. I would say that use of these techniques could remove maybe one allocation in eight, and use of writable strings one allocation in four.

It's no joke when people claim highly optimized C++ code can trounce the best possible Java code. It's the flat out truth.

Microsoft claims the overhead in using any of the .NET family of languages over C++ is about two to one. I believe that number is just about right for most things.

HOWEVER, managed environments carry a particular benefit in that when dealing with inferior programmers you don't have to worry about one module trashing another module's memory and the resulting crash being blamed on the wrong developer and the bug difficult to find.

Joshua
Mark Simpson
On pretty much any halfway decent garbage collector, heap allocation is just bumping a pointer, i.e. it is *exactly* the same as stack allocation. What is generally expensive is the actual collection of actual garbage, or more specifically, the actual collection of actual *old* garbage. That's why GCs run best with large heaps: they simply like to avoid collecting.
Jörg W Mittag
@Jörg: I know that. In stack allocation, both allocate and free is one instruction for all objects on the stack frame.
Joshua
meriton
FYI, if the unmanaged heap is allowed to waste RAM equal to allocated RAM, it can change both allocate and free operations to be O(log (n)) where n is the number of distinct powers of two sizes required to be allocated.
Joshua
+2  A: 

At least as I read it, your real question is whether there have been significant developments in garbage collection or manual memory management since that paper was published that would invalidate its results. The answer to that is somewhat mixed. On one hand, the vendors who provide garbage collectors do tune them so their performance tends to improve over time. On the other hand, there hasn't been anything like a major breakthroughs such as major new garbage collection algorithms.

Manual heap managers generally improve over time as well. I doubt most are tuned with quite the regularity of garbage collectors, but in the course of 5 years, probably most have had at least a bit of work done.

In short, both have undoubtedly improved at least a little, but in neither case have there been major new algorithms that change the fundamental landscape. It's doubtful that current implementations will give a difference of exactly 17% as quoted in the article, but there's a pretty good chance that if you repeated the tests today, you'd still get a difference somewhere around 15-20% or so. The differences between then and now are probably smaller than the differences between some of the different algorithms they tested at that time.

Jerry Coffin
+3  A: 

You seem to be asking two things:

  • have GC's improved since that research was performed, and
  • can I use the conclusions of the paper as a formula to predict required memory.

The answer to the first is that there have been no major breakthroughs in GC algorithms that would invalidate the general conclusions:

  • GC'ed memory management still requires significantly (e.g. 3 to 5 times) more virtual memory.
  • If you try to constrain the heap size the GC performance drops significantly.
  • If real memory is restricted, the GC'ed memory management approach results in substantially worse performance due to paging overheads.

However, the conclusions cannot really be used as a formula:

  • The original study was done with JikesRVM rather than a Sun JVM.
  • The Sun JVM's garbage collectors have improved in the ~5 years since the study.
  • The study does not seem to take into account that Java data structures take more space than equivalent C++ data structures for reasons that are not GC related.

On the last point, I have seen a presentation by someone that talks about Java memory overheads. For instance, it found that the minimum representation size of a Java String is something like 48 bytes. (A String consists of two primitive objects; one an Object with 4 word-sized fields and the other an array with a minimum of 1 word of content. Each primitive object also has 3 or 4 words of overhead.) Java collection data structures similarly use far more memory than people realize.

These overheads are not GC-related per se. Rather they are direct and indirect consequences of design decisions in the Java language, JVM and class libraries. For example:

  • Each Java primitive object header reserves one word for the object's "identity hashcode" value, and another word for representing the object lock.
  • The representation of a String has to use a separate "array of characters" because of JVM limitations. Two of the three other fields are an attempt to make the substring operation less memory intensive.
  • The Java collection types use a lot of memory because collection elements cannot be directly chained. So for example, the overheads of a (hypothetical) singly linked list collection class in Java would be 6 words per list element. By contrast an optimal C/C++ linked list (i.e. with each element having a "next" pointer) has an overhead of one word per list element.
Stephen C
Java strings can have their character arrays allocated in “interesting” ways (e.g., literals). There's a lot going on in the background that the API hides.
Donal Fellows
@Donal - true, but my point is that differences in Java vs C++ memory requirements are not *just* attributable to the way that memory management is done.
Stephen C
@Stephen: I'd agree with that. It's an area where the difference between good code and poor code is rather subtle, and that's true in many languages.
Donal Fellows
A: 

I am not sure how relivent your question still is today. A performance critical application shouldn't spend a sigificant portion of its time doing object creation (as the micro-benchmark is very likely to do) and the performance on modern systems is more likely to be determined by how well the application fits into the CPUs cache, rather than how much main memory it uses.

BTW: There are lots of ticks you can do in C++ which support this which are not available in Java.

If you are worried about the cost of GC or object creation, you can take steps to minimise how many objects you create. This is generally a good idea where performance is critical in any language.

The cost of main memory isn't as much of an issue as it used to me. A machine with 48 GB is relatively cheap these days. An 8 core server with 48 GB of main memory can be leased for £9/day. Try hiring a developer for £9/d. ;) However, what is still relatively expensive is CPU cache memory. It is fairly hard to find a system with more than 16 MB of CPU cache. c.f. 48,000 MB of main memory. A system performs much better when an application is using its CPU cache and this is the amount of memory to consider if performance is critical.

Peter Lawrey