Monday, April 30, 2007

You can't do that with Java

O.K., it's not that I hate Java. It's more, I run into times where I need to do something that I can't do in Java. Some of my favorite C++ features include operator overloading, crazy C++ templates like the ones you get with the Standard Template Library, and flexible memory management, not to mention the great job that C++ compilers do at optimizing all this magic into fast object code.

It's really the flexible memory management that I miss the most. Allocating memory out of the heap is expensive. That's pretty common knowledge. With Java, every Object gets allocated out of the heap. I remember the first time I ran into this early in my Java career. I had this little class that had a couple of fields that I used to store temporary information that got passed down to some other methods. I couldn't believe that I had to allocate it out of the heap. With C++ it had become second nature to declare an object and have it automatically allocated on the stack. And when the function I declared it in finished, whether due to a return or an exception, the destructor for the object gets called so you can clean up any mess. And using C++ pass by reference, I was able to do all that with minimal typing (my other mantra - I hate typing, especially with my sore finger right now).

The other cool feature of C++ is the ability to override the operator new to do your own memory management. That way you can allocate all instances of a class in a special memory pool. Or pass parameters to operator new to do anything you want. I've run into this as I've started looking closer at ray tracing algorithms (my new hobby). One of the speed ups they mentioned was allocating all contents of one of the structures in a given memory region to help leverage CPU data caches in an effort to squeeze every ounce of performance out of the machine as they can (which is really needed to get any resemblance of real-time ray tracing on today's machines). Now that's something you can't do in Java, at least not without some native code, which then isn't really Java.

Java has it's place and I love it for writing Eclipse plug-ins. But despite bold predictions by the IT industry, C/C++ will never go away as long as we continue to throw as much processing at these fancy new CPUs and GPUs as we are. For some reason, our appetite for speed continues to outstrip all that performance that the silicon vendors are working so hard to put in our hands.

11 comments:

  1. Man, you need to trust Java's just in time compiler. It can do all the stuff you like about C++ compiler but better. :-)

    ReplyDelete
  2. "With Java, every Object gets allocated out of the heap"

    This will be no longer true with Mustang and later releases of VM.
    I've tried these feature in debug release of VM Escape Analysis in Mustang.

    Agree, C/C++ will never lose it's niche, but as far as enterprise applications and the applications which don't need to know much about hardware are well handled in Java. I hope we agree that managed environment can always out-perform traditional compiler emitted code.

    ReplyDelete
  3. I agree that the memory allocation in Java is a bit crap, but there's no specific reason why the language|VM makes it so. It's just that there's been virtually no attempt by Sun to do anything new with memory (and thus, none of the other adopters have done the same).

    Objective-C partitions memory into NSZones, and you can have automatic memory allocation with NSAutoReleasePool. Typically, in an event handling loop, all transient objects are created with that thread's NSAutoReleasePool (which can be overridden at will) and at the end of the loop, can release all references created during the loop (that aren't referenced elsewhere). There's no reason why Java couldn't take advantage of this kind of system and expose it via the libraries without having to make the burden on object allocation fall directly to the user.

    Unfortunately, JVMs memory management are still very much in the dark ages, with a 'new generation' being the height of the technology in that area.

    And don't get me started about JVMs needing to allocate the entire block of memory in one contiguous space on Windows ... I mean, that's just crap. Granted, Unix systems have better memory management than Windows does (which is why it's not a problem on them) but the fact still remains that there's no reason why the heap *needs* to be allocated in one chunk from the get-go, only a pragmatic one.

    Sadly, even open-source VMs like Harmony are following the 'standard' route of working this way, so I don't expect that to be any different.

    Perhaps .Net will be a better managed VM after all?

    Alex.

    ReplyDelete
  4. Although Java does not support allocation of objects on the stack, its memory allocation is very efficient by using thread-local memory pools. I remember reading few years ago(!) that in most cases object allocation (with new) should translate into ~20 machine instructions.

    If you don't use anything special, C/C++ malloc/new calls can translate into very expensive OS calls.

    First I was excited about C#'s value objects, but then I was disappointed because their usage syntax is a bit misleading. AFAIK Java's CG is very much ahead of C#'s GC.

    ReplyDelete
  5. "I agree that the memory allocation in Java is a bit crap, but there's no specific reason why the language|VM makes it so. It's just that there's been virtually no attempt by Sun to do anything new with memory (and thus, none of the other adopters have done the same)."

    Alex as always is subtly bashing Sun :-).


    However, Sun changed a lot with memory allocation in Java - and there are still working to improve that even more in Java 7.

    Java 5 saw the introduction of Class data sharing: several classes are shared among JVMs.

    Java 6 made better use of register. In previous version, if no more registers were available for an operation, the compiler had to perform copy from register to memory (or memory to register), which takes time.

    Java 6 also saw the introduction of escape analysis. Escape analysis is the problem to analyze the dynamic scope of pointers. Pointers that do not escape from methods can be allocated on the stack. So allocation on the stack already exists on Sun JVM.

    For Java 7, other optimization based on escape analysis techniques are planned.

    ReplyDelete
  6. O.K., here's another example. Can you use the x86 SSE instructions and registers in Java? This is the kind of optimizations I'm talking about. VMs are good for performance, but I want to take advantage of all the capability that the RM (Real Machine) gives me.

    Yes, C/C++ will continue to have a niche, if you call the multi-billion dollar gaming industry a niche...

    ReplyDelete
  7. This is not a scientific test, but when using -XX:UseSSE=0 (turning off SSE, default is 2) results in a much slower execution of a sample floating point code.

    So my guess is that Java does use SSE.

    ReplyDelete
  8. I agree with Doug that Java lacks the ability to allocate objects on the stack. That being said, all people I see around me programming in C++ allocate everything they need on the stack not because it is appropriate, but because they fear that if they allocate their objects on the heap and pass pointers around, they will end up with a memory leak. Even experienced programmers do so! And so you end up with your program copying objects all over the place (I hate the way C++ has to copy objects all the time instead of moving pointers, spoiling the CPU cache and wasting cycles).

    By the way there are also some things you can easily do with Java that are quite hard in C++: one example is memory-sensitive caches implemented with SoftReferences.

    I would argue that both Java and C++ could be a lot better. I look forward for C++ 0x which apparently will have a (very controllable and optional) Garbage Collector.

    ReplyDelete
  9. Hi Doug. I also mostly dislike Java, but for different reasons. I do like how the Java platform abstracts away from the physical machine. What I don't like is how the Java language falls short on features. Many people who go from C/C++ to Java think of it as a major upgrade, but the truth is that Java is missing a huge number of features from modern programming languages. There is no DBC, no proper closures, no mixin inheritance, no type inference, no pattern matching.... How long did it take them to add a foreach loop, sheesh. The new features in Java 1.5 were a help, and thankfully there are some proposals to add closures to Java.

    I guess the goal when designing Java was simplicity, but to achieve that goal they left expressive power on the cutting room floor. Java is brutally verbose and virtually impossible to code in without an IDE.

    Anyone interested in a powerful, modern and elegant programming language should check out Scala.

    ReplyDelete
  10. if you call the multi-billion dollar gaming industry a niche...

    I just meant to express opinion of C/C++ future :-). Again, that market is not monopolized by a single language.

    Can you use the x86 SSE instructions and registers in Java?

    This can be never ending argument - but Yes we can do that in Java but in non-standard ways. Can it be done in C++ by specification? I would not be amused to see an example of it in C++ without asm. The good news is I can do everything that can be done in C++ (JNI), that's a big advantage to me :).

    ReplyDelete
  11. In 10 years of Java development, I have never caught myself wishing that I could "allocate memory on the stack". That just didn't happen. I wished for weak references, but those are now here.

    For non-GUI code, Java is plenty fast, and each iteration of the JVM improves performance. The idea is that instead of re-inventing the wheel over and over again, let the JVM handle it.

    I also just went back to manual memory management in Objective-C. And I have to say: Nothing is worth that! It's total garbage that I have to write allocs and destructors all over the place just to keep the system from getting out of hand. What an insane waste of time when the GC can handle 95% of that, and weak references can take care of the other 5%. It's like going back to the stone ages.

    As for Java being very verbose, and needing an IDE: Very true, that's what we have Eclipse for. Or IDEA if you like that better. Both are heaps and bounds ahead of XCode, and both succeed in making all drawbacks of Java go away.

    Again going back to something text-editor-like like XCode after being on Eclipse is like going back to the dark ages of computing. It makes no sense I should have to do all these things manually when the computer can easily do them for me. It's just a colossal waste of time.

    ReplyDelete