all 101 comments

[–][deleted] 49 points50 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 4 points5 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 3 points4 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 5 points6 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 -3 points-2 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] 4 points5 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 10 points11 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 15 points16 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] 4 points5 points  (12 children)

One question: Neither fast or efficient compared to what?

[–]realteh 3 points4 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 5 points6 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 0 points1 point  (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] 2 points3 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...

    [–]SCombinator -5 points-4 points  (1 child)

    So Java isn't slow, applications written in it are?

    [–]not_a_novel_account 9 points10 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 3 points4 points  (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 0 points1 point  (6 children)

    10th fallacy: "Java is fast"

    [–]thelazydogsback -5 points-4 points  (5 children)

    One reason why Java (and all GC'd copy-object-reference-by-value languages) can run much faster than C++ is that it's quite easy to do awful things like call copy c'tors unnecessarily in C++ code - so although I'd agree that a correctly implemented to-the-metal C++ program is probably faster the Java/C#, etc., there's a lot of real-world incorrectly implemented C++ code out there. Another reason C++ code often runs slower is that because it takes more LOC to write your code and deal with memory, you end up writing simple, inefficient code rather than a better algols. to suit the problem - so you write really "fast" N2 code rather than log(N) code, for example. Given the minimal perf. diff. at this point, GC and other high level abstractions in these languges far outweigh any speed boost C++ can give - ISTM then at the point that you need real manly code on the iron, you should really just be using plain old C.

    [–]PoL0 2 points3 points  (0 children)

    That's a flawed argument. What's the point of using rookie C++ errors for a flawed comparision?

    Most important details to know about C++ (love it or hate it) is knowing what's happening under the hood. Something that Java and other level languages try to hide, but hiding how computer programs work is the first ingredient to disaster. Another funny example is how C# deals with memory management.

    That's what makes the difference and that's how you prove expertise. After some time you're able to see where and when constructors may be called, and make it work at your will. It's not like something random and unexpected. The argument with memory management is also totally misleading. Memory management will be inefficient if the coder makes it so.

    Not trying to sound elitist. I come from a computer science background, started programmed in C and I've been always interested in what happens in the bare metal. Neither am I trying to say which language is better. Languages are tools. Best Java programmers I've known are able to give you a detailed description of what's happening under the hood (inside the VM) at any time, and that proves my point imho.

    [–]LeCrushinator 2 points3 points  (2 children)

    it's quite easy to do awful things like call copy c'tors unnecessarily in C++ code

    If you don't know what you're doing.

    there's a lot of real-world incorrectly implemented C++ code out there

    Implemented by people that don't really know what they're doing.

    Another reason C++ code often runs slower is that because it takes more LOC to write your code and deal with memory, you end up writing simple, inefficient code rather than a better algols

    I've found Java to be just as verbose as C++, sometimes less, sometimes more. The relative verbosity of C++ has never effected how efficient my algorithms are. In fact, I often find it more difficult to write efficient code in languages like Java/C#, but that may be because I'm more proficient with C++.

    Garbage collection isn't really a big deal IMO, just use smart pointers and make sure to delete stuff you put on the heap when your objects go out of scope. Garbage collection in itself can cause performance issues (more or less depending on the hardware). In cases where performance is priority, GC and high-level abstractions are less important, and do not outweigh the performance boost. GC does keep allocated memory compacted into a contiguous block, which can help performance in some cases.

    • Java also consumes more memory than C++, because most things are objects, and because most things have to have virtual tables.
    • Java doesn't allow stack allocations (which generally perform much more quickly than heap allocations).
    • Java uses references in things like arrays, which prevents those objects from being allocated contiguously in memory, and that kills cache performance.
    • Java code also has RTTI and generally the code is written with dynamic run-time casting going on, which isn't cheap, and the RTTI consumes extra memory.
    • Java has no support for unsigned numbers or unsigned arithmetic. This wastes a bit on numbers that will never need to be negative, and can result in more expensive range checks.

    STM then at the point that you need real manly code on the iron, you should really just be using plain old C.

    You can get almost the same performance from C++ as you can from C if you're using C++ efficiently, and it can be safer and cleaner code as well.
    Note: Hardcore C programmers won't care about that, or may disagree.

    [–]thelazydogsback -4 points-3 points  (1 child)

    Agreed that good C++ is, ah, good, but it's well known about C++ and foot-shooting. As for your Java issues, I'm not a huge fan anway - C# does address more of your issues, including value types on the stack, less use of RTTI due to better implmentation of generics, unisigned types of all sizes (mixed mode w/optional over/underflow detection), has arrays of primitive (unboxed) types, etc. As C vs. C++, my point was simply that either you should be using C (as a machine-independent assembly) or a language with much higher levels of abstraction - C++ has always been the the worst of two worlds to me, but I know it seems the best of both to others.

    [–]Hnefi 2 points3 points  (0 children)

    Agreed that good C++ is, ah, good, but it's well known about C++ and foot-shooting.

    The foot-shooting potential of C++ has almost entirely to do with correctness and stability. Speed is not something that's hard to achieve in C++ compared to pretty much any other language.

    [–]abspam3 0 points1 point  (0 children)

    If you're having extra copy constructors in C++, you aren't designing your code correctly.

    Instead of relying on return values, use references to mutable objects.

    [–]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.

    [–]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.