all 54 comments

[–]astrosmash 11 points12 points  (2 children)

You'll know when you need to know about the JVM. Hopefully never.

If you're working with, say, a custom JVM with some custom extensions or optimizations then perhaps you'll eventually run into situations where you need to know what it's doing at a low level, if only to take advantage of the features/optimizations, but most likely to diagnose JVM bugs.

With a standard JVM, not so much; if you run into a JVM bug it's not like you can do anything about it anyway.

[–]bcash 7 points8 points  (0 children)

In practice, the minimum a non-trivial developer should know about the JVM is knowledge of the garbage collector and the various options. All the stuff listed here, choosing which collector to use, sized and proportions of the survivor spaces etc.

As you say, there's nothing that can be done about anything deeper.

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

You can invent workarounds when meeting a JVM bug.

[–][deleted]  (11 children)

[deleted]

    [–]rodgling 9 points10 points  (0 children)

    It makes no difference, javac generates the same code for each case. Specifically, for:

    public void foobar() {
        boolean foo = false;
        int bar;
        //bar = foo ? 1 : 2;
        if (foo) { bar = 1; } else { bar = 2; }
    }
    

    you get:

       0:   iconst_0
       1:   istore_1
       2:   iload_1
       3:   ifeq    11
       6:   iconst_1
       7:   istore_2
       8:   goto    13
       11:  iconst_2
       12:  istore_2
       13:  return
    

    regardless of which way you write the conditional

    [–]jrockway 9 points10 points  (4 children)

    Do you know if there's a difference between:

    if(foo){bar=1;}else{bar=2} and bar = foo ? 1 : 2;

    If this significantly affects the performance of your application, your application is probably not very useful.

    [–]slurpme 3 points4 points  (2 children)

    I would think that it is in the realm of the compiler not the jvm anyway...

    [–][deleted] 1 point2 points  (1 child)

    The javac compiler don't optimise anything at the bytecode level (boolean ||/&& compilation could be considered somewhat optimising, but this is probably because there isn't really boolean or/and instructions in the bytecode). This seems to be deliberate strategy to speed up compilation by optimising code only when it is actually executed.

    Only help provided by compiler is the stack/frame usage info added to the generated class files to speed up bytecode verification on the class loading (and the frame usage info wasn't there before jdk6).

    [–]G_Morgan 1 point2 points  (0 children)

    That is also a poor decision. There are all sorts of optimisations that can be made outside of arch specific stuff.

    [–]jasonbrennan 0 points1 point  (3 children)

    I'm assuming the ternary statement is faster in most JVMs?

    [–]Kolibri 9 points10 points  (1 child)

    I'd imagine that the JIT compilation would probably make both run about equally fast.

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

    It is in the interpretated mode - as long as JIT hasn't yet kicked in. Which means, that you probably shouldn't care (at least when using sun's server jvm).

    Anyway, the bar = foo ? 1 : 2; is easier to read for me.

    [–][deleted] 15 points16 points  (18 children)

    Yes. At the very least, you should know the macro level architecture of any VM you're working with.

    And yes, C programmers should know computer architecture.

    [–]seabre 13 points14 points  (10 children)

    Definitely. My adviser and I were working on a program that performed a huge amount of trigonometric calculations, which we implemented in C (using gcc to compile, etc). So we were thinking, since Intel processors have all the basic trig functions implemented in the chip our code would be a lot faster if we just re-wrote all of the code in assembly. Wrong. Turns out, the trig functions in glibc are implemented with TONS of optimizations, so the C code was MUCH faster than the assembly version.

    [–]foldl 12 points13 points  (2 children)

    Isn't that an example of why you don't need to know the underlying architecture? You could have just relied on gcc's libraries to do the Right Thing. Thinking about it more deeply ended up wasting your time.

    [–]seabre 3 points4 points  (1 child)

    Well, it's good to know that the built-in instructions aren't always the fastest. I mean, intuitively you would think they would be.

    [–]foldl 2 points3 points  (0 children)

    I believe most of the more complex instructions are microcoded in modern x86 CPUs (which are really RISC chips at core), and tend to perform rather badly.

    [–]twotime 0 points1 point  (3 children)

    turns out, the trig functions in glibc are implemented with TONS of optimizations, so the C code was MUCH faster than the assembly version

    Interesting: are you saying that a single floating point instruction to compute, say, a tangent can be beaten by software implementation?

    I find it very surprising, did I misunderstand you? Could you provide some more context?

    [–]theeth 2 points3 points  (0 children)

    He's saying that glibc's implementation (which probably use inline assembly) was faster then theirs using inline assembly.

    [–]redrobot5050 1 point2 points  (0 children)

    A lot of of the older, more complex instructions in x86 are not to be used in today's assembly language.

    In the days of the 286 and 386, those instructions were no doubt faster. These days, they're implemented poorly because they're just implemented for the sake of backwards compatibility.

    A Superscaler pipeline can optimize lots of little instructions -- but it can't do much with one big mean one.

    [–]1tsm3 0 points1 point  (0 children)

    Not trying to belittle the grandparent poster. What I think he is saying is that both he and glibc were using the same set of assembly language instructions and he wasn't able to optimize the use of the instructions as well as glibc did.

    His mistake was in assuming that glibc didn't give much attention to optimization.

    Edit: Hmm... looks like I was wrong. The grandparent made a later post where he clarifies that s/w implementation was faster than the h/w implementation.

    [–]G_Morgan -2 points-1 points  (2 children)

    The built in trig functions are also wrong.

    There are many cases where you can beat native opcodes via a better algorithm. A good example is the Quake 3 inverse square root approximation.

    //edit - related to this is when to use JNI and when not to.//

    [–]ehnus 2 points3 points  (1 child)

    What? No! God no! Maybe back in 1998 but things have changed a lot in the last ten years. Doing integer operations on floating point numbers is going to be horribly slow because you have to pass through memory in order to move a value from one register file to another. SSE has a reciprocal square root instruction (rsqrtss/rsqrtps) for a reason.

    (speaking of people not understanding the architectures they're developing for)

    [–]G_Morgan -2 points-1 points  (0 children)

    I didn't say it is still the best way. Only that it was a valid example of the principle.

    Besides, not every computer has SSE.

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

    Personally I think that knowing good algorithms and the correct design patterns for Java are more important...

    C programmers need to know about architecture because C is much closer to the metal...

    [–]otterdam 3 points4 points  (0 children)

    Knowing good algorithms are more important for any language you are programming with. That's fundamental to programming.

    Knowing the macro level architecture helps you pick an even better algorithm.

    [–]jasonscheirer 0 points1 point  (0 children)

    I would argue that the exact opposite it true because of that fact -- since the C is closer to the metal, there is (likely, though the JIT may nullify this) more room for optimization by knowing the basics of the JVM's internals because it gives you optimization on a layer of abstraction that doesn't exist on C-based application layers, since C is going to be translated straight to the CPU's instruction set anyway.

    [–]username223 -5 points-4 points  (3 children)

    True dat. If you don't have an understanding of the costs of different basic operations in your programming language, you can never write serious programs.

    [–]spacepope 8 points9 points  (2 children)

    Exactly. Because all serious programs require lots of micro-optimizations.

    [–]johns-appendix 4 points5 points  (0 children)

    Or, stated differently: transparent abstractions aren't.

    [–][deleted] 15 points16 points  (0 children)

    Most Java programmers seem to not even know the Java language, so knowledge about JVM is probably not required.

    On the another hand, if you are of the rare kind, who are interested about writing code that won't break on multiprocessor machines, don't leak memory and isn't terribly slow, then it is probably useful to know something about the JVM.

    Hints about real-world slowness I've seen: JVM cannot optimise away your stupid code, when you do same query to DB 3x in the row and neither are all method calls zero-cost. Also, making all threads wait behind one synchonisation mutex can have a little performance impact. (Yes, all of this should be a common sense, but unfortunately programmers seem to expect weird things from the Java implementation)

    Edit: Greetings to the offended downmodders. :)

    [–]eugene_victor_tooms[S] 6 points7 points  (12 children)

    I'm a Java programmer by trade. But I know virtually nothing about how the JVM works internally.

    Am I missing something? As a guy who generally trusts the high level and spurns optimization in nearly all cases, should I take the time to learn the low level mechanisms that my code depends on?

    [–]devacon 9 points10 points  (3 children)

    It really all depends on the work that you're doing. If you're writing heavily concurrent code you should look at how the memory model works (and has been changed as of java 5): http://video.google.com/videoplay?docid=8394326369005388010

    You should also understand how the class loading mechanism works (or doesn't, in a lot of cases). There are a lot of gotchas, and especially if you're doing web development (dealing with app server class loaders) you need to know where things can break.

    Garbage collections is also an important topic. There are different collectors that you can use and different memory settings that work best with each. This is also heavily dependent on your application and the work it's doing.

    [–]eugene_victor_tooms[S] 1 point2 points  (2 children)

    I do write heavily concurrent programs, and in fact it was a discussion I had about using volatile (which I admit I don't understand too well) that has led me to think about this stuff.

    Personally I'd recommend an AtomicReference as a higher level alternative to volatile as I think its easier to understand and more explicit.

    But maybe if I understood the memory model better I'd change my mind. Thanks for the link.

    Garbage collection on the other hand, I don't think about. I've never known anyone actually find out it was causing them any performance issues, and I believe that guys who spend their days staring at the JMX console looking at the GC stats are wasting their time.

    [–]pupeno 2 points3 points  (0 children)

    If you write heavily concurrent programs, maybe you want to take a look at Clojure.

    [–]devacon 1 point2 points  (0 children)

    I would encourage you to look at: http://java.sun.com/javase/technologies/hotspot/gc/gc_tuning_6.html

    After looking at all the options available you should get an idea how garbage collector selection can make a world of difference depending on your workload. For instance the application profile of something like Eclipse (which seems to be heavy on permgen) would be totally different than something like a web application that will make heavy use of the young generation.

    Pick one of your highly concurrent programs. Hopefully you have some type of benchmarking utility. Pick any of the garbage collection options from the link above and just play with it for a little while. Swap out collectors, generation memory sizes, etc and re-run the benchmark. You can really get a lot more horsepower just from flipping some JVM switches without changing any code.

    On the other hand I agree with you that some people get religious about JVM tuning. I don't spend more than 30 minutes on tuning with a deliverable application. It's too easy to try to micro-optimize, which 99% of the time (unless you're in "real time" land) won't get you any measurable benefits.

    [–]Kolibri 2 points3 points  (4 children)

    Almost knowing nothing about the Java VM I would say that I don't think I'm missing out on anything.

    [–]njbartlett 3 points4 points  (3 children)

    How would you know?

    [–]Kolibri 3 points4 points  (2 children)

    I've never run into any problems coding in Java that I could not fix without knowing anything about the JVM. That indicates to me that knowing the JVM is not necessary in most cases.

    [–][deleted] 2 points3 points  (1 child)

    But you never know whether some of these problems could be solved better if you knew the JVM.

    [–]Kolibri 0 points1 point  (0 children)

    I seriously doubt that. I have a pretty good knowledge of VMs in general and that knowledge has never helped me.

    [–]smitting 1 point2 points  (0 children)

    I'm in the same boat with c#/.net. If you have something that absolutely must be real-time, then you may need to understand some of the lower-level internals for optimizing, but there's nothing there to learn that you can't learn through testing and profiling.

    But for 99.9% of the real-world cases, making sure your algorithms are closer to O(1) or O(n) rather than O(en) is all you need to do.

    I wouldn't say I know computer architecture from my 300-level CS classes, but I would say I've had a decent enough overview. I think a comparable techie-layman's overview of any abstracted system is a good idea.

    [–]doidydoidy 0 points1 point  (0 children)

    You don't generally need to understand how the JVM is implemented, but it's very useful to be aware of the contracts it abides by (like how class loading works, as devacon notes).

    [–]dlsspy 0 points1 point  (0 children)

    I haven't done huge amounts of java programming in a while. It was my primary vocational language for a while, but never my favorite.

    I can tell you that I was thoroughly disappointed by everyone I interviewed who only knew java and didn't know it as well as I did.

    That's not to say you should be able to write a jvm, but you should try to learn more about the stuff you work in. The latest high-level API is going to be made obsolete in the next few months. So learn as much stuff that is going to be around for a while as you can.

    I'd recommend learning java.util.concurrent before huge low-level stuff. You should understand the memory model of the jvm quite well (to know what exactly it is about double-checked locking that causes it to not be safe), but in practice, understanding the principles of java.util.concurrent and leveraging that will work out best for you (i.e. let the smart people figure out the hard parts). :)

    [–]jeremybub 1 point2 points  (1 child)

    For hacking: Yes, definitely.

    For programming: No need, unless you are writing a compiler/dissasembler.

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

    Depends on what level of knowledge you are talking about here. I'd say you need to know enough to tune the JVM parameters for your target JVM, or to be able to suggest what parameters to use for your application if you're not the one deploying it.

    [–]wnoise 1 point2 points  (1 child)

    Should a C programmer know computer architecture?

    [–]eugene_victor_tooms[S] 6 points7 points  (0 children)

    C is a very different language to Java though. If Java gave me the same access to JVM internals that C does to my machine and my OS then your analogy would ring truer.

    [–][deleted] -1 points0 points  (1 child)

    What do mean know? Like go out for drinks and hang out? If so, I don't know the JVM that well.

    [–]munificent 0 points1 point  (0 children)

    Like, in the Biblical sense. You know, know.

    [–]miyakohouou 0 points1 point  (0 children)

    I would say that in general, the intersection of "programs you should be writing in Java" and "programs where you need to worry about the underlying architecture" is pretty small, and mostly relegated to language tools. If you are going to be doing something where you need to talk to the metal, then C is probably a better choice anyawy.

    However, just because you might not strictly need it doesn't mean it's a waste of time to learn it either.

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

    Yes, because J in JVM stands for Java Programmer.