Java Performance Urban Legends
An anonymous reader writes "Urban legends are kind of like mind viruses; even though we know they are probably not true, we often can't resist the urge to retell them (and thus infect other gullible "hosts") because they make for such good storytelling. Most urban legends have some basis in fact, which only makes them harder to stamp out. Unfortunately, many pointers and tips about Java performance tuning are a lot like urban legends -- someone, somewhere, passes on a "tip" that has (or had) some basis in fact, but through its continued retelling, has lost what truth it once contained. This article examines some of these urban performance legends and sets the record straight."
I wonder to what extent this exists in other languages? For example, there is an oft-cited tip that says using persistent database applications with LAMP applications increases performance. I've found in actual practice that this depends on a lot of factors such as server load, amount of available memory, etc.
I remember in my Turbo Pascal programming days (heh) that a lot of people said that using Units would degrade performance. So I tried it both ways and it never really made a difference, for my applications anyways.
I'd say before taking someone's word for it on a performance enhancing technique, test it out. Because not everything you read is true, and not everything you read will apply to every environment or every application.
My journal has hot
The best tip in the article, which really applies to any language (even to choice of languages), is IMHO
"Save optimizations for situations where performance improvements are actually needed, and employ optimizations that will make a measurable difference."
sigh, I can't believe I misspelled it twice
No, you didn't. You misspelled it once; the second time is simply being consistent.
Misspelling it twice would be writing "optomizing" and "optomezing"
has poor start up time, and requires an absolutely massive amount of memory. That, and garbage collection makes almost-real time ("soft" real time I believe is the technical term) UIs more difficult than they should be.
Oh, good, another one to shoot down. While I don't have any numbers at all, I know that Apple 'fixed' this problem to an extent by making parts of java shared, just like any shlibs. This alleviates the 14 apps, 14 bags of shit problem to some extent.
Apple then returned the changes to SUN, who rolled them into 1.4.x.
I wish I had numbers. Sorry.
Exactly how does "string require careful attention"? I've seen this statement a couple of times, but only to suspect that many people don't really understand what Java Strings are.
The first mistake, of course, is that people think that (a == b) == a.equals(b) which is, of course, only true if a and b are constant strings or one have invoked intern() on them.
The second is to not realize that string concatenation with the "+" operator is a special case and only syntactic sugar for StringBuffer operations. Thus, someone not familiar with Java may accidentally generate huge amount of StringBuffer objects in loops.
However, both these things are very fundamental Java knowledge and among the first thing you learn when studying Java. It's obvious that you don't start coding serious Java without knowing how try..catch..finally works, and equally obvious that you should the know about the deals with the String class.
I think he's talking about something like this:
/* snip */
while(true)
{
Object o = new Object();
o = null;
}
The GC won't free the memory in realtime (or, sometimes, ever), as would be the case for C++/C with new/delete malloc/free.
Do you even lift?
These aren't the 'roids you're looking for.
I'm all for calling a spade a spade, but you can't have your cake and eat it too.
JNI is the NATIVE INTERFACE. For those that don't already know, that's the interface to the underlying operating system. If the OS misbehaves, hiccups, or is inconsistent, when did it become JAVA's responsibility to clean up? When somebody decided that JAVA was getting a black eye because OS call foo(bar) was crashing the application, or better yet didn't behave exactly like foo(bar) on every OS that provides the JVM.
Don't like AWT? Well mabye that's because it's built on top of JNI. Enough said.
Don't like Swing? Well you'd better like AWT. If you don't want the OS to do your GUI work and you don't want the JVM to do your GUI work, mabye you should just get a dry erase marker. You can draw the boxes you need on the screen provided you use a tissue between display updates.
String requres no more attention than any other bit of JAVA code. If you create dozens of objects for the sole purpose of garbage collection, you either just learned JAVA, you're unaware of what you're doing, or you don't care.
And about garbage collection. JAVA's garbage collection may not be your cup of tea, but neither are the memory leaks that are still being cleaned up in systems that lack automatic garbage collection.
So pick your posion. If JAVA isn't perfect, that dosen't make it horrible. JAVA is a good language by most standards, but be honest by stating that it isn't good by your standards.
My biggest reason for liking JAVA is that it forces people to stop writing bad C code. Which is exactly what it was designed to do.
I wonder to what extent this exists in other languages?
Probably lots. Everywhere.
As a crude approximation, 90% of the time is due to 10% of the code. Improving the "efficiency" of the 90% of the code that is responsible for only 10% of the time tends to be counter-productive. Of course there are no easy magic rules for how to improve the 10% of the code that is responsible for 90% of the time, or even identify exactly what that 10% really is.
What does work is to have a sense of how long things should take and find and cure whatever is taking much longer than it should.
Yes, if I need speed, I use C, the same as anyone else. If I am writing a Web application, I use Java. That's an area where Java excels. And maybe I'll get lucky enough to be able to code a project in Assembly or Lisp, who knows? Programming does not follow the "jack of all trades, expert at none" theory. General concepts map well across the spectrum.
I find it discouraging that there are so many programmers who only want to learn as much about their job, as to merely be good enough . Don't they feel any pride, or any desire to excel at something?
Coders who can only handle one language should be paid minimum wage; that is all they are worth. That is because it is neither the language nor the implementation that is important. It is the knowledge of how to program which will ensure your career and pay your bills.
A lot of them are things that actually used to be good advice, but for some reason or another (changes in hardware, compilers, etc.) aren't anymore. For example, it used to be a good idea in C to iterate through arrays by incrementing a pointer and dereferencing it instead of incrementing an index and then using array subscripting -- that way you had one increment per iteration, instead of one increment plus one offset calculation (basically you saved the addition that takes place during the array subscripting). However, on many modern C and C++ compilers in many situations, array subscripting will actually be faster than the pointer-incrementing method, because it's easier for the compiler to perform certain optimizations with. [Reference: Michael J. Scott, Programming Language Pragmatics (Morgan Kaufmann, 2000).]
There's quite a bit of other stuff like this out there as well.
10 PRINT CHR$(205.5+RND(1)); : GOTO 10
Java is not always slower. Java's interpreted nature is generally seen as a weakness, but it has advantages too. For example, the JIT has profiling data immediately at hand when doing optimization, whereas compiled languages won't. Even in cases where compiled languages do use profile feedback, it may not be representative of the current program usage.
Try writing a simple recursive Fibonacci number calculator in both C++ and Java. The Java one is faster, when using a JIT enabled JVM. Of course, that is a contrived example, but it shows that just-in-time compiling can be faster.
One of the reasons is that interactions with caches are hard to model, making it hard to know what to do to minimize problems. Caching is, inherently, a deal with the devil: you get speed but lose understanding. Sometimes you lose the speed too. Even when you understand, there's not much you can do. Sometimes complicated stuff is inherently expensive.
When I say caching, I mean not just CPU caches of RAM, but also RAM caches of (potentially swapped-out) process space. If you allow a naive garbage-collector to operate freely, it will happily consume the entire address space available, typically the sum of available RAM and swap space, before garbage-collecting, so the process will run not from RAM but from swap. When it garbage-collects, too, it has to walk a lot of that memory, and swap it all in.
Just running "ulimit -d" in the shell where the java (or other GC-language) program runs can help a lot. It will GC a lot more often, but if nothing is swapped out, the GC happens a lot faster, and the program's regular execution doesn't have to touch swapped-out pages. You have to know a lot about the program and the data it uses to guess the right ulimit value, and if you guess wrong the program fails, but a thousand-fold speed improvement earns a lot of forgiveness.
Did you really believe garbage collection would mean you don't have to know about memory management? It makes memory management harder, because the problem remains but there's less you can do about it. (For trivial programs it doesn't matter. If you only write trivial programs, though, you might as well find some other job.)
There's a similar effect with the CPU cache and RAM. Ideally you want the program code and the data it operates on all to live in cache, because touching the RAM takes 100 times as long at touching cache. With bytecodes, you have a lot more "cache pressure" -- you have the bytecodes themselves, the just-in-time compiler, and the native code it generates. At the same time, since your memory manager generally can't re-use memory that you just freed, it allocates other memory that, when touched, pushes out something else that was useful (such as program code).
The result is that no matter how clever the JVM is, there's not much it can do to get the performance of real programs close to optimal, or even within a pleasing fraction of equivalent C++ code. This despite all the toy benchmarks that seem to prove otherwise, and which carefully avoid all these real-world problems.
Of all the promised features of Java (like Lisp before it and C# after it), we're left with the sole remaining feature, that its virtual machine specifies precisely (or abstracts away) enough details of the runtime environment that the code is more portable than a faster native implementation, and the code might get written faster for the author having avoided thinking about details that affect performance.
The sole saving grace is that most programs don't have much need to run very fast anyway, or if they do it's hard to prove that they ought to run faster. Most people take what they get without complaining, or without complaining to anybody who cares, or without doing anything to make whoever is responsible uncomfortable enough to have to do anything differently. A whole generation trained to accept programs that crash daily or hourly is thrilled to find a program whose biggest problem is that they suspect it might be sluggish.