top | item 3836398

Java IAQ

75 points| Mitt | 14 years ago |norvig.com

31 comments

order
[+] krrose27|14 years ago|reply
Goes directly to "What other operations are surprisingly slow?" and attempts to write micro benchmark with the same results.

Fails....

Most of the general stuff is accurate and dandy but I don't believe you should listen to many (most likely any) of the speed related statements as this article appears to have been written in 1998.

Topic should be "Java IAQ circa 1998".

[+] nailer|14 years ago|reply
I have an IAQ of my own:

Why is it that Java VMs seem to have such different interactive latency when compared to other memory-managed language VMs? Is the performance of eg, eclipse or Android or the Java browser plugin something to with the GC kicking in too aggressively?

Over the last decade I've heard different explanations re: SWT/swing/AWT toolkits, and server-side optimizations being default in desktop VMs, but I'm fairly sure both issues should be resolved now. Nevertheless, my general experience seems to be if it's Java based, it seems to handle touch/mouse events noticeably worse than otherwise.

Maybe .net and Python and the rest are doing more of their UI work in C?

[+] mbell|14 years ago|reply
This has a lot more to do with the GUI toolkits than the JVM. Python is most often used with bindings for GTK (C), QT (C++) or tk (C). I don't know a lot about .net but I believe it just links to the standard windows gui toolkit probably also written in native code.

For Java the main issue is that Swing/SWT/AWT suck and java is mostly used as a server language so there is little impetus to fix them.

Eclipse is just bloated, that is why its often slow. Android has its own custom JVM (Dalvik) but I imagine the majority of the UI rendering / handling code is native with Java bindings.

All that said, the full JVM (both openJDK and sun's) have multiple garbage collectors and many tuning options. This creates flexibility to tune the GC for particular work loads but also makes them complicated to work with. It doesn't help that the default GC/memory settings in the JVM are a bit...off, and use the high throughput GC vs the low pause collectors.

[+] lars|14 years ago|reply
It's been a while since I've done work in Java, but I'm pretty sure the GC is not to blame for this. Java uses a concurrent mark and sweep GC. The concurrent part means it does not pause the world while it's collecting. So as mbell says, it has to do with the UI frameworks.

But I don't think it has to do with whether or not the UI code is written in C either. In the UI frameworks I've used for both Python and Ruby, you could write slow interpreted code that would run on the UI thread. The key thing was you tended not to do it, because the frameworks didn't encourage you to do so. The problem is that Java frameworks make it easy to for example do IO on the UI thread, whereas the other frameworks make it hard. Threading is relatively hard to get right in any of these languages, so the choices made by the framework authors really matter.

Another thing contributing to Java being perceived as being slow is the long boot time of the JVM. (It used to be slow at least, don't know if it still is.)

[+] nvarsj|14 years ago|reply
It's pretty simple... Hotspot collectors are optimized for throughput, not latency. That's where the money is for Sun/Oracle. It's a trade off between one and the other in any garbage collector.

You can tune it to some extent.

[+] sehugg|14 years ago|reply
It's the libraries. Write an app with OpenGL or SDL and it works fine. (Minecraft is a perfect example)
[+] smackfu|14 years ago|reply
If you are interested in this kind of stuff, Effective Java is a must-read book. Long, good explanations of how to do stuff right.

Also, the 2nd edition covers up through Java 1.6.

[+] stiff|14 years ago|reply
I second this recommendation, actually even if you do not program in Java nor on the JVM. Like no other book it taught me a particular kind of foresight - to analyse the consequences of each small decision being made during implementing some new thing and to design things in such a way that they are least likely to cause problems now or in the future, to me or to other programmers working on the project - my code is much more solid and less error-prone ever since and it was definitely a big AHA moment for me. The author, Joshua Bloch, designed some of the standard Java APIs and I actually can't think of a better way to learn about those things than implementing an API used by other people, which explains why he has so many interesting things to say that are seldom found in other places. Here is also a very nice talk by the author:

http://www.infoq.com/presentations/effective-api-design

[+] js2|14 years ago|reply
FWIW, last changed July 13, 1998 according to the source.
[+] peeters|14 years ago|reply
This appears to have been written before IDEs were invented. The author suggests that it's acceptable to extend a class just to gain unqualified access to its static methods to save a few characters of typing.
[+] tptacek|14 years ago|reply
Did you read "Scheme In One Class" at the link he attached to the paragraph you're sniping at?
[+] typicalrunt|14 years ago|reply
Java compilers are very poor at lifting constant expressions out of loops. The C/Java for loop is a bad abstraction, because it encourages re-computation of the end value in the most typical case. So for(int i=0; i<str.length(); i++) is three times slower than int len = str.length(); for(int i=0; i<len; i++)

Does anyone know if this is still valid advice? I recall reading somewhere that the JIT has optimized around this problem.

[+] Someone|14 years ago|reply
For this example, I would expect that any decent Java compiler optimizes this away nowadays. That does introduce a dependency between compiler and standard library, but the benefit is large enough, given that this is idiomatic code, and that Java has it easy here because Java strings are immutable.

For general collections, things are more difficult, but I still expect java to optimize things in many cases. I haven't checked, though.

A C/C++ compiler has a tougher job. It can only move strlen calls out of a loop if it can determine that the strlen you call came from the correct <header> file and that there is no defined behavior under which either the pointer or its contents change inside the loop.

If it cannot do either, it must 'call' strlen each time through the loop (That 'call' can be inlined, especially if the compiler knows it is the standard library's strlen)

[+] krrose27|14 years ago|reply
The thing is String.length() doesn't do any re-computation. All it does is return a variable defined in the String object that is modified when the string it contains changes.

See my other comment saying you should ignore any speed suggestions by the article.

[+] smackfu|14 years ago|reply
I like this way to rewrite it when the end test is slow (I think this is correct syntax):

for(int i=0, len=str.length(); i<len; i++)

One evaluation and you don't have an extra len variable hanging around.

[+] typicalrunt|14 years ago|reply
But note the warning from Sun: "So when should you use static import? Very sparingly!"

I'm so glad there is an authoritative answer on this subject. IMHO, I hate the use of static imports because it becomes difficult to know where a particular method comes from... where it's an instance method from the class itself or one that is brought in through a static import.

And then there's the possibility of clobbering the namespace by including a local variable name and a statically imported variable.

[+] peeters|14 years ago|reply
I don't like them in general either, but there's one place I use them extensively: JUnit tests (statically import Mockito, Hamcrest, Assert, etc).

It mostly has to do with how much the library tries to be a DSL, and how much readability will suffer if I don't use a static import. IMO, this

  assertThat(6, isGreaterThan(5));
reads a heckuva lot better than

  Assert.assertThat(6, Matchers.isGreaterThan(5));
Of course the combination of poor Java type inference and Generics-heavy libraries make it so that often I have to do the latter to make use of angle braces, but that's another story.
[+] Drbble|14 years ago|reply
I don't understand this comment at all.

Do you not know that import statements are at the top of every class file, or did you mean that you hate wildcard imports? Do you also eschew local variables, because they might clobber fields and method parameters if you ignore the compiler warnings?

[+] lucian1900|14 years ago|reply
A little outdated, the one about HashMaps and equals is moot with generics.

Still quite interesting.

[+] codeflo|14 years ago|reply
It's not. HashMap<K, V> works exactly like Hashtable with regards to equals() and hashCode().
[+] swah|14 years ago|reply
Its not like Java is changing that much :)

Is this still true these days: "creating a new object is a fairly expensive operation" ?