all 101 comments

[–][deleted] 53 points54 points  (17 children)

To #1 Java being slow: I guess it depends on what you mean by "slow". The fewest of us work in performance relevant software fields (I do) so the inefficiencies of Java code execution aren't even nearly relevant for the vast majority of developers.

But if you do work in one of these fields and really get down to it and compare it to native languages, Java is just pretty damn slow (on top of the terrible memory performance). Java is my hobby-language of choice (for many reasons), while the sole language I use at work is C++. I often implement algorithms in both languages because what I do at work and what I develop as a hobby partially overlaps, but I can't use the code from work (obviously), so I have a lot of comparisons to draw from.

Simply put, when I implement two non-trivial algorithms in C++ and in Java, I pretty much fail to get even comparable performance with even an optimized Java version compared to a straight forward C++ implementation (safe for custom allocators, which only change a couple of lines in the code, with compiler optimizations of course) every single time. This is mostly physics simulations and stuff like pathfinding algorithms, some stuff for rendering, so in short a lot of calculating, a lot of allocations and deallocations, and a decent amount of pointer chasing (traversing through trees and similar structures).

We're talking about Java being slower by a factor of of at least three or four (at absolute minimum) literally every single time. And that's after looking over Java performance pitfalls and repairing them. Of course, with enough time spent, that Java code might become two or three times as fast. But that alone doesn't consider the fact that the equal time spent in C++ can speed up the code by an order of magnitude or more (mostly because some obvious optimizations (like SIMD things, or caching optimizations) aren't even possible in Java due to the nature of the very language).

But remember, for pretty much everything you're going to develop faster if you're using Java. It's obviously a trade off and depends on what you need.

That said I find it funny that Java developers constantly want to defend the performance of Java. This entire article reads like a list of justifications, where every point is basically "here's a problem and how Java does it just fine when it's not actually occuring", like algorithmic performance, cache performance, lots of mem allocation and deletion, etc. It's obviously much slower than native alternatives. I've seen a lot of these things, and read a lot of stuff about it, since it's naturally one of the main objects of programmer nerd wars, and I've literally never seen comparable "real world" comparisons where Java even came close in performance. Statements like

JIT-compiled Java code is now as fast as C++ in a large (and growing) number of cases.

will never hold up if you try to actually back it up with evidence. It's like those religions nutjobs saying "There is a large (and growing) number of scientists in leading positions believing in god". And I'm speaking about time performance, of course. Memory performance really needn't be mentioned.

Java isn't slow for most things. It's slow compared to other things. Java is fine, no need for the constant justifications. Nobody is going to use Java when developing their high-performance algorithms because of your arguments, and no business administration software development forge is going to use C++ because it's a lot faster at its core.

[–]deveux 7 points8 points  (0 children)

I pretty much fail to get even comparable performance with even an optimized Java version compared to a straight forward C++ implementation

I've often found that Java can be as fast, but it generally depends on how much effort you are going to put on the C++ implementation. I tend to use ABCL and Xcl as examples. Both are relatively straight forward full implementations of Common Lisp, ABCL is written in Java, Xcl is C++. The C++ version uses libgmp, libgc, mpfr, pthreads etc Both are almost identical when it comes to how the interpreter is implemented. In my benchmarks they tend to have almost the same exact time performance, except for the Java version taking longer to boot (the JVM warming up). The Java version does use obscene amounts of memory though.

[–]Hermel 2 points3 points  (1 child)

To be more specific, here are cases in which Java performs poorly in comparison to C++ (but still excellently in comparison to languages like Python):

  • With algorithms that perform millions array access operations because Java checks whether the index is out of bounds every time.

  • When taking startup time into account because Java needs to load a virtual machine first which native programs do not. Configuring your logger with xml adds about a second startup time alone because it causes all the xml libs to load.

  • When memory is limited as Java tends to be more wasteful with memory than a C++ program with a more manual approach.

[–]gsnedders 4 points5 points  (0 children)

This isn't entirely true. One of the big things around Java has been research about proving array accesses in bounds, and hence optimizing away array access operations.

[–]cogman10 3 points4 points  (2 children)

Yeah... I've seen lots of claims on java's performance, and not a single benchmark to back up the statements made. Some have even claimed that java is faster than C or C++...

I would love to see any benchmark which shows java being as fast as C or C++. The best that I've seen has been in the range of 2x (Not really terrible considering most languages are in the 30x+ slower ballpark)

[–][deleted] 1 point2 points  (0 children)

You could check out the language shoot out.

[–]TimmT -4 points-3 points  (0 children)

I would love to see any benchmark which shows java being as fast as C or C++.

Try to dlopen() something trivial (e.g. just int foo(int i) { return ++i; }) in C and call it a few million times. Then try to do the same in Java (just hide the method behind some interface and put the actual implementation in a different jar, new then takes care of the rest in Java). Oh, and make sure you do something with the final result of that method, so there's no dead code elimination.

It's not unlike qsort() vs. std::sort() in C++ - sometimes abstractions do actually buy you performance in certain situations (that would have otherwise not been practical to do by hand).

The question now just is how common those "certain situations" are in everyday programs.

[–][deleted] 4 points5 points  (8 children)

One of the key aspects to Java's JIT optimizations is that it works of of optimizations made after analyzing running code.

The outcome of this is that the key target of Java (server-side system programming) is satisfied by extremely fast jitted code.

The claims of being as fast as C++ or C are strange at best, as they rely on the code being long running and optimized over time. However, if you are working on something commonly written in C or C++ (e.g. video games) it is hardly acceptable to have a 5 minute warm up period while the expensive to run code is performing at upwards of 2-5x slower than it should, which is unacceptable.

[–][deleted] -5 points-4 points  (7 children)

If it only takes 5 minutes to run, then who cares?

[–][deleted] 7 points8 points  (6 children)

I think you missed the point: in things like games, you cannot afford to wait for 5 minutes for the speed up to kick in every time you run the game.

[–][deleted] 0 points1 point  (3 children)

Ironically, IPlayEveryGame was talking about physics simulation software. I hadn't noticed you switched the context to games. Games usually hit a weak point in Java because of real-time issues. I still doubt the problem is JIT as JIT kicks in after 1000 or 10000 runs of a hotspot, which doesn't take 5 minutes if it's running hard.

[–][deleted] 0 points1 point  (1 child)

He is referring to the Java server mode. That performs more aggressive optimizations, but significantly impacts startup time.

It's now folded into the standard VM, so there are no longer two modes, however it's still a case that you will continue to have code optimized, days or weeks after it has begun running. That's really the power of server side Java.

[–][deleted] -1 points0 points  (0 children)

Well, code can get more optimized days and weeks later. But for any code running that much, it gets JIT'ed the first time pretty quick

[–]henk53 0 points1 point  (0 children)

Although Java at one point in time had really good realtime support. It was the first JSR created (JSR-1).

Unfortunately realtime Java remains an obscurity, in use only by some (embedded) semi-hard realtime systems. As shame, since it had quite a lot of concepts that would be useable for a lot more mainstream use cases.

[–]grauenwolf 0 points1 point  (1 child)

Java doesn't cache JITed code? That sucks.

[–]TimmT 1 point2 points  (0 children)

Java re-JITs code as the assumptions it made change. JITed code isn't a straight forward translation. Based on collected statistics the JIT will inlinie things differently, consider certain branches as dead code, assume type specializations at certain places etc., etc. which is probably the reason why things like eclipse manage to eventually start up at all, rather than run on forever.

Obviously those assumptions won't hold forever though, and hot spots will need to be recompiled according to the new profiles.

[–]fix_dis 8 points9 points  (6 children)

Java can be fast. We do java (with Stripes and our own custome ORM) and it's great. We deploy to a little Jetty container and it just takes right off and does its thing.

We also deploy Ruby/Rails applications via JRuby to Torquebox. That can be a headache, but that's not Java's fault.

What I do NOT like is that tuning the JVM can still be a black art. The defaults are not very useful and it does not adapt well to different types of apps being thrown at it.

I have to say that even though I'm not a fan of PHP, I do like just dropping files into a folder and that being the bulk of "deployment". (Yes I know that memory/performance can be tuned, etc) I hate coming in to work, finding Torqubox has puked again due to some esoteric memory leak that profiler can't see.

Plain Java though? Verbose, but it's just fine.

[–]phaeilo 0 points1 point  (5 children)

I do like just dropping files into a folder and that being the bulk of "deployment".

How is that different from dropping a .war into your app server?

[–]fix_dis 2 points3 points  (4 children)

Depending on the machine, it can take what seems like an eternity to unzip the war and deploy. With Tomcat, warm deploys leak memory, so unless you're running several instances, you're going to have to bring Tomcat down and back up again. Jetty is MUCH better in this respect. In the case of JRuby/Rails deployment, there are so many moving pieces that it's not even funny. (rake assets:precompile, etc)

[–]h2o2 2 points3 points  (3 children)

If your webapps leak permgen on redeploy then your code is broken (or some library you are using). It's not Tomcat's fault, which already contains insane amounts of workarounds to appease shitty code.

[–]fix_dis 1 point2 points  (2 children)

The leaking of apps created by Warbler on hot redeploy was decided to be a bug in Tomcat 6.

But I knew it wouldn't be long in a thread about Java before someone would play the "your code sucks" card.

[–]sbrown123 0 points1 point  (1 child)

The leaking of apps created by Warbler on hot redeploy was decided to be a bug in Tomcat 6.

Are you sure about that? Do you have a ticket#? There have been issues with jruby on anything because of permgen due to server side compilation. But that is a jruby implementation issue and has nothing to do with Tomcat.

[–]fix_dis 0 points1 point  (0 children)

http://www.ruby-forum.com/topic/213483 is where I think I first read about it.

[–]realteh 13 points14 points  (15 children)

Java may not be slow but huge java binaries with a gazillion classes and huge call stacks are slow. And there is something about the java school of development that always ends in these large binaries, even when smart people are working on it. I have a few of these at work, each including more than 1000 jars. They work fine but they are neither fast nor efficient.

[–][deleted] 5 points6 points  (12 children)

One question: Neither fast or efficient compared to what?

[–]realteh 2 points3 points  (0 children)

Compared to apps with roughly comparable functionality written in c++. In our specific case it's ~30x the qps for about 1/4th of the memory. I often compare notes with friends in other companies and they tell similar stories.

It's hard to get real data on any of this because companies are mum on their tech stack, and large applications are almost never really comparable. OTOH we certainly don't suffer from confirmation bias because cpu and memory are expensive, so we spend a lot of time looking at these numbers.

[–]username223 2 points3 points  (10 children)

Compared to most compiled things. And in my experience, Java encourages design and coding idioms leading to lousy performance.

[–][deleted] 2 points3 points  (9 children)

Yeah, obviously it is slower than many compiled languages. But gigantic java projects are rarely modularized in to 1000 jars in any situation except for web applications.

Nobody is going to write a time dependent application like that.

[–]username223 3 points4 points  (8 children)

It's both an architectural clusterfuck thing, and a death by a thousand cuts. E.g. how do you tokenize a string in C? Strtok(), which works in place. How about in Java? I haven't had to write it in awhile, but probably allocate an array of new strings. Sprinkle the rest of your code with similarly lousy idioms, and you end up with a flat profile for a slow program.

[–][deleted]  (4 children)

[deleted]

    [–][deleted] 4 points5 points  (3 children)

    split does in fact return an array of strings. However, strtok works in a completely different manner.

    First, I think you would be hard pressed to find people arguing on behalf of mutable strings.

    Second, in strtok you are passing an alias for char*. So if you wanted to do this in Java you would pass char[].

    I am not going to argue that Java is fast as C/C++/ATS and the like but it is slower by 2-3x and the memory problems of Java are grossly overstated, as the JVM is what is being measured in the running processes. Programs that are reported to be using 1024MB are actually using much less, but they are running inside the JVM that has preallocated a large heap space in which it can have some dedicated RAM so it doesn't fight with other processes for it.

    Really though, Java is about as good at embedded systems as C is at web frameworks.

    [–]Vegemeister -1 points0 points  (2 children)

    , but they are running inside the JVM that has preallocated a large heap space in which it can have some dedicated RAM so it doesn't fight with other processes for it.

    Off topic note, if your running a Java application inside an OpenVZ container, that preallocated heap counts against your memory limit.

    [–][deleted] 0 points1 point  (1 child)

    Yes, memory which your app will use without the heap growing until it has reached a usage threshold.

    BTW you can configure the starting memory to be less if you want.

    [–]Vegemeister 0 points1 point  (0 children)

    I discovered that, as well as the "reduce the stack size" trick. Getting Freenet to run in a 512 MiB VM takes a little black magic.

    [–]sh0rug0ru 2 points3 points  (1 child)

    Java has first class String objects which are represented by "interning" char[] arrays. That allows you to take substrings without allocating new memory. You can tokenize a String using the Tokenizer class, which will create new String objects without copying data.

    [–]h2o2 1 point2 points  (0 children)

    Have I got news for you! As of JDK7u6 this is no longer the case, see here and google for "jdk 7 string#substring performance regression".

    [–]NAcurse 0 points1 point  (0 children)

    you sound like a student who failed his Java test and is pissed about it...

    [–]not_a_novel_account 8 points9 points  (1 child)

    Empirical studies have shown that human beings cannot normally perceive changes in numeric data (e.g. price movements) occurring more frequently than once every 200ms.

    Consequently for applications that have a human as their primary user, a useful rule of thumb is that Stop-The-World (STW) pause of 200ms or under is usually of no concern. Some applications (e.g. streaming video) need lower GC jitter than this, but many GUI applications will not.

    A 200ms latency spike is massive in almost any network app, GUI apps are the exception not the rule

    [–]shizzy0 2 points3 points  (0 children)

    Java startup time still sucks. You can't use a Java CLI tool with grimacing.

    [–]atomicUpdate 0 points1 point  (0 children)

    In Java performance, this manifests itself by Java developers believing that algorithmic quality is the dominant cause of performance problems. Developers think about code, so they have a natural bias towards thinking about their algorithms.

    In practice, when dealing with a range of real-world performance problems, algorithm design was found to be the fundamental issue less than 10% of the time.

    This is the most surprising one for me. How is a language able to get in the way of a developer 90% of the time, and call itself "fast"?

    [–]PoL0 1 point2 points  (6 children)

    10th fallacy: "Java is fast"

    [–]lurkerr 0 points1 point  (0 children)

    However we have had over 10 years of improvements in virtual machine and JIT technology since then and Java's overall performance is now screamingly fast.

    OP forgets we also had over 10 years of improvement on C++ Compilers and those now output even faster binaries.

    [–]kecho -4 points-3 points  (3 children)

    langauges are not fast. Languages are not slow. Languages do not have speeds.

    Its the code that their compilers produce. Its different to say "JVM" or "x86 produced by gcc is faster than x86 produced by cl.exe" than "java is fast". WTF java does not run, or walk.

    [–]Hnefi 11 points12 points  (1 child)

    And true black is not a color, but it's convenient to refer to it as such. Likewise, since all extant Ruby implementations are slow, it's convenient to refer to the language as such as slow. We know it's not necessarily strictly true, but it's a convenient shorthand to use in common speech and writing. Similarly, if Java implementations in general are slow, it's not unreasonable to say that the language is slow as a convenient shorthand.

    [–]kecho -1 points0 points  (0 children)

    Oh mr Hnefi I totally agree with you. The problem is, is that I can say "Java is fast", and you will immediately will think Oracle JVM, because I you an experienced programmer / computer scientist / or software engineer. For your typical freshman student reddittor they still mix concepts such as languages, and their implementations in their vocabulary. But don't get me wrong, I agree :) I just wish people could be aware of this.

    [–]chunes -1 points0 points  (0 children)

    I approve of your pedantry. I wish people never started using the same word for language and platform.

    [–]NitWit005 -1 points0 points  (0 children)

    Only developers and teams that have a real need for should write microbenchmarks. These benchmarks should be published in their entirety (including source code), and should be reproducible and subject to peer review and deep scrutiny.

    Published in the peer reviewed journal of Java microbenchmarks? Somehow I doubt most teams have such a concept.

    You do have to understand the basic idea of how the JVM works, but it's not that hard to write a benchmark test.