Java Urban Performance Legends
An anonymous reader writes "Programmers agonize over whether to allocate on the stack or on the heap.
Some people think garbage collection will never be as efficient as direct memory management, and others feel it is easier to clean up a mess in one big batch than to pick up individual pieces of dust throughout the day. This article pokes some holes in the oft-repeated performance myth of slow allocation in JVMs."
How much time have I spent with Electric Fence and valgrind finding memory leaks in my C programs? In Java, the auto garbage collection is as good as Perl's, without that tricky "unreadable code" problem ;). And I can always tune garbage collection performance by forcing a garbage collect when I know my app's got the time, like outside of a loop or before creating more objects in storage.
--
make install -not war
The memory allocation management routines are normally running when the JVM thinks it's best, but as a programmer it is usually possible to predict the best time when to actually take care of the housekeeping. Even if the memory management cleanup takes the same time in both cases Java has a tendency to issue them in the middle of everything. So if I as a programmer does the garbage collection at the end of a displayed page and Java does it uncontrollable in the middle of the page the latter case is more annoying to the user.
If builders built buildings the way programmers wrote programs, then the first woodpecker would destroy civilization.
I've had many professors say that Java is nowhere near as slow as it used to be, and that it was just a myth now that it is that much slower the C or another language that doesn't rely on VMs. In most applications, I guess it's actually equal enough to C to be considered as an alternative. Although it doesn't have anywhere near the rich number of libraries C/C++ works with (I'd like to see someone make a cutting edge game in Java).
In undeveloped countries, the consumer controls the market. In capitalist America, the market controls you.
What Java apps are you talking about?
There aren't many professional-grade Java Desktop apps out there, and those that _are_ out there are generally built for maintainability, not speed (Eclipse, Netbeans). I built a Java web client that blew the pants off its older C++ version. The reason Java apps are generally slower is because the Java culture is about maintainence over performance.
Don't even get me started on C#.
.Net violates the EULA. And we
wouldn't want that!
I should hope not! Any form of benchmarking of Microsoft's
So when Microsoft declares their interpreted inverse-polyglotic language as "faster" than compiled pure C, just accept it. Best for everyone that way.
the FACT is that people's real-world experience, no matter how anecdotal, consistently demonstrates that Java is MASSIVELY slow than similar apps in C or C++.
Well, the linked article contained a number of what I will graciously call "assumptions" (rather than "outright lies") about allocation patterns in C/C++ that simply don't hold true in most cases.
For example, the parent mentions the old "stack or heap" question... Which no serious C coder would ask. Use the heap only when something won't fit on the stack. Why? The stack comes for "free" in C. If you need to store something too large, you need the heap. But then, you can allocate it once, and don't even consider freeing it until you finish with it (generational garbage collection? Survival time? Gimme a break - It survives until I tell it to go away!). As for recursion... You can blow the stack that way, but a good programmer will either flatten the recursion, or cap its depth.
And the article dares to justify its "assuptions" by comparing Java against a language interpreter such as Perl. Not exactly a fair comparison - Yes, Perl counts as "real-world", but in an interpreter, you can't know ahead of time anything about your memory requirements. At best, you can cap them and dump the interpreted program if it gets too greedy. Now, some might point out that Java gets interpreted as well - And I'll readily admit that, for doing so, it does a damn fine job with its garbage collection. But if you want to compare Java to Perl, then do so. Don't try to sneak in a comparison to C with a layer of indirection.
One last point - The article mentions that you no longer need to use object pooling. SURE you no longer need it - Java does it implicitly at startup. You can avoid all but a single malloc/free pair in C as well, if you just steal half the system's memory in main(). Sometimes that even counts as a good choice - I've used it myself, with the important caveat that I've done so when appropriate. Not always. I don't have malloc() as the second and free() as the second-to-last statements in every program I write. And that most definitely shows in the minimal memory footprints attainable between the two languages... Try writing a Java program that eats less than 32k.
The copying collector sounds really fast indeed, but I can immediately see two problems:
The first one is the need for a huge amount of memory. It would seem that the optimal way of dealing with this is restricting the amount of memory available to the application, otherwise any app can grow to the maximum size allowed by the VM, whether it needs it or not. But this sounds rather crappy to me, now every developer needs to figure out an right limit for the application.
The second is that performance is going to suck when garbage collection is performed. The slowdown could be a lot larger than a single execution of malloc/free, especially if virtual memory is taken into account. The unused half of the memory will often be quickly moved to swap by the VM, especially when the process grows to sizes in the order of hundreds of MB. Then GC will force bringing all that back to RAM, while possibly swapping the previously used half to disk. Exactly the same situation as what's described with heap allocation, but a whole lot worse.
It sounds to me that even if malloc is slower, it's a lot less inconvenient in applications like games, where something that is always slow can be taken into account, but where a sudden run of the GC could be really inconvenient.
But this is not my area of experience, so it's just what came to mind. Can anybody confirm or refute these suspicions?
Here is a paper (PostScript) from 1987 on the topic of GC being faster than manual allocation.
The author went on to make a very fast GC that set speed records.
If you are looking for factual arguments, with performance measurements and so on, just look at his work over the last few decades -- you'll see he did a lot of work in these very practical areas.
When you see how productive guys like him can be, it makes me wish that some people would just stay alive, and keep working, for a few hundred years more, instead of our typical mortal lifespans.
http://www.thebricktestament.com/the_law/when_to_
Programmer cycles are expensive.
Indeed. It might be worth (pardon my pun) reiterating what those cycles really are, in regard to application performance.
In all languages I know of, you get some library functions ready-made, and you need to code some stuff yourself.
Most performance problems occur in the code you made yourself.
In my experience, you get most bang for buck when you are able to efficiently allocate your programmer time to a) program a functionally complete draft version, b) optimize those parts which need optimization and c) maintain the program, in a manner which is BALANCED, but biased towards maintenance.
De facto, you get better balance between those things, and most bang for buck, using languages such as Java, as opposed to languages such as C++, because (say) Java offers a pretty coherent conceptual framework (class libraries) for creating your draft in a maintainable way, provides default access to excellent non-invasive performance measurement tools such as YourKit and JProfiler which let you objectively find out where you need to do performance work.
This means you can do only the optimization work that is necessary, and create optimized packages which extend the default class library interfaces which means that generally maintenance programmers don't have to put nearly as much work into figuring out how the optimizations affect the draft work.
It's not perfect, but it gets you more bang for buck, which is what matters to you when you manage resources.
Not the default developer perspective, I know.
The article's main point is that Java's memory allocation is faster than malloc, and it's garbage collection is better than cumulative free's.
However, thats not the problem. All memory in a Java program has to be allocated dynamically. Other languages offer static memory alternatives. Static memory use will be more efficient in many cases.
The my language is faster than yours argument is inherently stupid. There is no "best" language. You need to use the right tool for the right job.
--Barry
Well, as my own "real life experience" is concerned, programming in Java is a lot simpler, faster and less prone to bugs than programming in C++.
In addition, I bear witness that Java applications are faster than C++ applications.
I still use C (NOT C++) for simple, host system-level tasks, though, as it is a good system-level language (heck, *nix are C-based, after all)
In short : I concur with the submitter.
OP's comment is based on the fact that Java is usually deployed on those big iron Sun boxes (8-way minimum, 16-way, 32-way etc. with 32Gb RAM etc. - you get the picture.) Any darn thing runs reasonably fast on these machines. And when things execute in-memory and are JIT'ed there is no reason to believe Java code will execute slower than say C/C++ code. Plus lots of design patterns have grown to make up where Java performance sucks - Use huge thread pools to avoid creating threads on demand, cache as much as you can, pool objects to avoid doing new on big objects etc. Java/J2EE makes it possible to write robust server side applications quickly without having to deal with low level details. People pay a big price for this by having to buy those big boxes on the server side. It could be argued that smart C/C++ programmers can build something more reliable/scalable with less resources - but matter of the fact is that world is full of lazy "high-level" "abstract" "mediocre" programmers. Destop is a different matter altogether - people still have machines with mere 256Mb RAM with one pale CPU - C/C++ rocks there. Java sucks badly on the desktop - Graphics/Drawing is slow, startup time is horrible, simple apps can require boat load of memory and on top of this the UI looks nasty. Just a data point - Microsoft's VC# IDE requires 29Mb - it's written in C/C++ and embeds the C# VM. Netbeans and Eclipse - last I checked they needed atleast 100Mb!
I have been doing Java programming for several years now and ported many C/C++ applications to Java, mostly server side apps and I'd say roughly 85% of the time the Java apps outperformed the originals, sometimes by an order of magnitude. Now these were more redesigns than straight ports and the performance gains were not because Java was any better from a performance standpoint, but because design is more of a factor in speed than the language used, especially for larger applications. Usually when I find big performance hurdles that are hard for me to overcome, I find I would have same issues in most languages, so finding a better design is usually the solution. If you are writing small - medium apps or mostly GUI apps then I might have reservations about Java, but for larger apps Java is a good choice.
I've never believed that Java's garbage collection is the root cause for its slowness. I do believe that Java's GC is the cause for its random (and more notably, its inconveniently timed) stutters.
I think the more general Java slowness comes from the obfuscation of efficiency. In C for instance, ugly code correlated with inefficient code. This is no longer the case for object-oriented programming in general, and it is possibly worst correlated in Java.
The example in the article provides a starting point for what I'm saying. It's based on the algorithm for a point in some Cartesian graphics system:
The Component.getDistanceFrom() algorithm is considered "good OO style." By using bad style, though, you can break the pretty encapsulation -- and make "bad OO style" -- but get a performance gain:
Both code blocks require the math (two subtracts, two multiplies, an add, and a square root) but the original block (unoptimized) also requires the allocation of the Point object and the two memory copies to store the (x,y) location.
This is a trivial example, but my point is that in a complex Java project, readable and elegant code bears no correlation to fast and efficient code. I believe this is why Java is slow.
--- Jason Olshefsky
Karma: Poser (mostly affected by adding this line long after everyone else did)
The common code path for new Object() in HotSpot 1.4.2 and later is approximately 10 machine instructions (data provided by Sun; see Resources), whereas the best performing malloc implementations in C require on average between 60 and 100 instructions per call (Detlefs, et. al.; see Resources).
Wow, that's really shocking. Until you actually look at the Detlef paper and realize that it was published in 1994, 11 years ago!! Who knows, maybe things have improved a bit in 11 years. The author certainly thinks Java is getting better; maybe it's possible that C/C++ compilers have improved as well.
Simply put there may be fast efficient tiny java programs out there but I don't see them.
If Java was as bad as you say it would NOT be so popular in embedded devices. There is a huge disconnect between the archaic concept of Java as a slow pig and the real world popularity of Java on small systems like printers and cell phones.
Hear that glass breaking? That's your credibilty going out the window... The statement i++; where i is an int will produce exactly the same code with ++i; and i=i+1; on an optimizing compiler, and no extra memory (or registers) will be used. Note that i is an int, not an object with overloaded operators...
Here's a problem: write the same programm, but don't use any extra variables.
A typical mobile phone is sub-ghz too, and there is plenty of J2ME software running on them...
Java rocks on limited devices AND as server software. It is only on the desktop it isn't a big hit. Yet.
Ha! That's a good one. I work with mobile phones, though I personally don't use J2ME. All the programmers I work with do though (the carrier chooses). J2ME really sucks.
The J2ME spec has a lot of fuzzy places and "MAY"s. You will find the full spectrum of possibilities in such places. There are also many imlpementations that blatently fail to meet the spec. (I've heard that boolean operators *sometimes* short-circuit, but I'm not sure I believe that.)
Fixed point math is common for these small systems. In Java, you end up looking like Lisp. FP.sqrt(FP.add(FP.mul(a,a),FP.mul(b,b))); Yuck. In C++, you look like C++. sqrt(a*a+b*b);
Then there's the jar size limits. Some phones only give you 64k to work with. And on top of that, each new class and function adds to the size of your app. So if you want to do some nice modular OO design, forget it. With C++, no problem. There are no size limits (aside from usable memory) and extra classes/functions are nearly free. Again, in C++ you can reuse loops and wrapper code to shrink code size, passing in a function pointer for the inner part. In Java? The extra overhead for the class you'd need to work that way cancel out the benefit.
Garbage collectors typically used in J2ME are way behind server and client versions. And when they don't work well enough automatically, system.gc() might force a garbage collection. Maybe, if you're lucky and the manufacturer felt like implementing it.
J2ME phones are almost universally one notch slower than the BREW equivalent. Some of the Samsung phones have poor performance under BREW, but are simple dreadful with J2ME. It's the difference between getting 4-5 frames per second and getting 1-2 seconds per frame. And if you're doing funky stuff with bitmaps that the phone has a slow implementation for, in C++ you can walk around the implementation and do it yourself. In Java, you're screwed.
J2ME is a joke.
BTW - your solution allocates about 4 squigabytes of memory, but that's OK because it all gets allocated by someone else, so it doesn't count. ;)
Most memory leaks I have seen in C come from the simple fact that it is not possible to allocate space on the previous stack frame. If the runtime included a mechanism for moving an allocation to the caller's stack frame (which would be trivial to implement) then most of them would go away. One other work around for this which I have seen is to have separate call and data stacks. Rather than calling malloc, you call a function which gives you a block of RAM on the top of the data stack. The data stack can be pushed and popped independently of the call stack, so a function that needs to return an arbitrary amount of data simply allocates it on the data stack, and returns a pointer to it. The pointer remains valid until the next time the data stack is popped.
I am TheRaven on Soylent News
It must be, so far I'm running Eclipse and/or Oracle JDeveloper on all the following platforms with no problems:
Dell P4 2Ghz 512MB RAM, Windows 2000
Toshiba P4 2Ghz laptop 512MB RAM, Gentoo Linux (2.6 kernel)
Athlon XP 1900, 1GB RAM, WinXP/Gentoo Linux dual boot
I will give you a caveat. JDeveloper was pretty crusty until version 10G came out. Runs pretty nice now. Eclipse is no problem on any of them. If you are doing Struts development, I can tell you that I was occasionally running out of RAM at 512MB. Of course, I'm running JDeveloper, a J2EE server, and my app all at the same time, so that's not too crazy.
I'm not saying they don't run like crap on your machine, I have no idea. All I know is that the company where I work, we have a few hundred people with the exact same machine specs that I do, and we don't have the problem that you are having.
All these things eat the shit out of resources, but they do not run slow, so I half agree with you, and I half don't. I don't know what the problem is that makes it take up all the resources, but java is not slow. I've been playing with JOGL, an OpenGL java wrapper library, and no one would mistake the results for slow. Maybe this is unfair, but rendering 2D OpenGL in Java is WAY faster than rendering native GDI in Windows.
Also one more point I would like to make: The point of Java is write once run anywhere. Sure in theory I can use the same application on multiple operating systems. The problem is that many of them have specific version requirements for the JVM I am using. Even with 2 or 3 Java applications on my PC there is a trial and error process of trying to find a JVM that all 2 or 3 applications can run on.
So I can write _one_ application and run it anywhere, as long as noby elses Java application using a seperate JVM version is already there.
Saying Java is nice because it works on all OS's is like saying that anal sex is nice because it works on all genders.
Startup of Java seems a little slower than CLR but not markedly slower. Mono's startup is hardly a speed demon either. In all, I think most of the hype around the CLR is just that - hype. The CLR is a lot nicer virtual machine, and C# is as close to C++ / Java that I couldn't care which language I'm writing to, but the performance differences are IMHO neglible.
As an example of how fast Java is, I have written a poker simulator which plays 1000 games from a deck of cards which is shuffled 1000 times for each game. The hands from each game are then sorted, and scored. It's very Vector and LinkedList intensive and each loop probably sees a dozen or so temporary Vectors or arrays used during comparison - i.e. 1,000,000 iterations with many more nested within. It takes just over a second on my 1.8 Ghz PC.
As far as I'm concerned, that's plenty fast. I reckon I could probably halve the time if I bothered to replace all the vectors with fixed arrays.
It would be hard to compare Delphi (as in traditional Delphi) to either C# or Java since it is a compiled language. I don't know what Borland are doing with it these days so I wouldn't be surprised if it's gone the CLR route too.
Unless, like me, you're the guy who's writing that library that everyone else depends on, in which case the two are the same thing for practical purposes. In that case, trust me, you still use something like C or C++.
Here are a few reasons why:
Any of those in isolation is game, set and match against the arguments in the article. Put together, you get the same picture most of us have painted all along: Java's performance is adequate for non-critical tasks, but it's nowhere near the top of the pile when it really matters.
BTW, in case anyone's wondering: yes, I do work on widely-used, performance-sensitive mathematical library for a living, and yes, as it happens I really have spent the last few weeks researching ways to increase the performance of that library even further.
If you disagree, post your argument. (-1, Overrated) isn't your personal censorship tool for views you don't like.
And when resources get really tight C is no longer an appropriate language to use. Many microcontrollers have less then 128 bytes of ram to work in. Often the program has to be stored in less then 256 bytes of ROM. C does not cut it in those environments. Welcome to our assembler overlords. C also has to be cut down to run on these low end devices. floating point divisions, 32 bit mulitplications, 16 bit additions...well they are not supported. The J2ME IS cut down. However it does specify a basic set of operations you must implement on the chip (or emulate in a layer in software)
"Remember, with Java you still have the overhead of a virtual machine. And that counts towards program and resource size (sometimes, significantly)."
The processors I'm playiung with at the moment run java byte code natively. You would have to have a virtual machine to run C on them. Rememeber, C is only efficient in some situations because the bytecode (machine code) it produces maps directly to the platform it is running on. Java and other "interpreted" langauges are designed to run on a machine that you may not have, so generally they are run on an interpreter. That does not mean that a machine to run the code directly does not exist.
I started off looking at the x86 instruction set and then googling for "XCHG reverse string" and voila, came up with this page that, aswell as covering some some of the methods described in this little discussion tree, has a final comment thats extra-specially interesting:
Of course, if you didn't trust your compiler (or working toward multiple architectures) you could always use some compiler directives and some embedded asm?
Is it possible to write this function using nothing but reigsters and the memory occupied by the string? Anyone care to give it a go? >)
While I agree that in theory, and in labratory conditions, Java is just as fast (sometimes faster) than C/C++, in practice it doesn't usually end up that way.
.NET available instead.
The way normal people write code, and the libraries and functions that normal people use, java is slow as snot. I don't care why that is, it just is, and it makes me steer away from Java client applications if there is something that is native or
Real world results are different from labratory ones as far as Java is concerned in my book. And that's just my experience.
If you need web hosting, you could do worse than here
A quick web search turns up several surveys with lots of benchmarks,
http://java.sys-con.com/read/45250.htmr k.html
http://www.idiom.com/~zilla/Computer/javaCbenchma
This is about as much of a myth as the myth of the earth traveling around the sun. There is a lot more to allocating memory than this article lets on. Psuedocode will always be slower than machine code no matter how you slice it. You can do various tricks to make it seem faster by instruction count at certain things but in the end those same things can be applied to compiled code like c/c++. Most people can accept that as fact and move on using Java where it seems appropriate. Make all the excuses and extraordinary claims you wan tint the end Java is just plain old FAT n slow, anyone in any programming course who has used java can tell you that.
Oh and it is hard to test out his little theory on the free malloc in C++ because you can't do the same thing in Java. You can try but it will get around to the free part when it gets good and ready and may not attempt the malloc until you use the memory.
Ermm, one question: is your poker simulator multi-threaded? If not, try ArrayLists in place of your Vectors in the Java code. Vectors are internally synchronized, which will hit you for a pretty big performance penalty.
Sorry, Vector over-use is one of my pet peeves. It's silly little programming goofs like this that make our programs slow, and give the anti-Java trolls more ammo.
"In a 32-bit world, you're a 2-bit user. You've got your own newsgroup, alt.total.loser." -Weird Al
I believe that this battle can be summed up in the battle of Java vs. PHP. Here we have a fully OO VM based language that has been widely deployed on both Unix and Solaris, vs. a (mostly) UNIX only scripting language turned web programming language with lots of web-specific features. I have developed large solutions in both languages, and it really comes down to: PHP rocks for quick-and-dirth websites. Put a PHP next to a Java guy to develop a basic ecommerce or content mgmt website, and PHP will TOAST that guy. Now required six-sigma reliability, 100+ hits per second, redundant servers w/ clustering, the ability to connect to multiple corporate database from different manufacturers, and other high-end enterprise features, and Java wins hands down. Not to mention of the security of PHP vs. the security of Java - PHP is "wide open" in many ways. USE a big hammer for a big nail, and a small hammer for a small nail. Java ran WebMD (many thousand hits per second, all data driven) with an early version of Java 1.1. - yes, we need to clean up the socket code some w/ SUN, but it worked, and it worked very well. The future looks to me .NET - Microsoft was brilliant - a well defined software app network architecture what is language agnostic. This time in a few years there will be many Java programmers writing web-service code behind the .net standard.
Thanks for reading my stream-of-consciousness.
Horns are really just a broken halo.
I'll try one more time. There is no rule that says the compiler has to translate function calls and return into assembly-language (stack-based) calls and returns. There is a technique, known as continuation passing, in which returns are never used. You may educate yourself by acquiring Appel's book "Compiling with continuations" or by reading Guy Steele's master's thesis or, indeed, by reading the references already given.