Live data from Hacker News

JRE 8 needs more codecache than before

engineering.indeedblog.com

21–30 of 38 posts

Re: JRE 8 needs more codecache than before

#21
post #4

How much Java source code does it take to need 256MB of codecache? The author says they're using a service architecture where each transaction uses about 20 services. There's no indication of why their program is so huge.

Author here. We know 128MB codecache was not enough and 256MB was sufficient. I think we could have gotten by with less, e.g. 200MB, but we stopped experimenting once we found a value that worked. We don't have a complete understanding of why this app uses so much more codecache than other apps we've switched to Java 8. Now that we expose the codecache size in Datadog, I may try plotting code size vs codecache size f…

Datadog employee here, you don't need to run your own collector to collect codecache usage. As it's exposed through JMX, the JMX collector can collect it http://docs.datadoghq.com/integrations/java/ . It doesn't by default though, so you'll need to configure it to collect the metrics from the "java.lang:name=Code Cache,type=MemoryPool" bean. We should add that in our default configuration.

Re: JRE 8 needs more codecache than before

#22
post #13

Typical problem of over tuning. Not every tunable needs to be tweaked (or worse cut'n'pasted somewhere from the internet). Your street cred as a admin does not depend on how many settings you can change. If they had just kept using the defaults everything would have been fine. That said 250MB is really a lot of code. Their binaries must be gigantic. This by itself likely already causes performance problems because al…

Yes but he said it was previously only 50mb. That 250mb contains a lot of duplicated compiles: tiered compilation can generate not just two but up to I think 5 different compiles of the same methods! I think code cache management in Hotspot is not that great: eventually the server would probably converge on a bit higher than 50mb due to the more aggressive inlining, but 5x suggests the low value compiles aren't being properly discarded.

Re: JRE 8 needs more codecache than before

#23
post #8
post #4

How much Java source code does it take to need 256MB of codecache? The author says they're using a service architecture where each transaction uses about 20 services. There's no indication of why their program is so huge.

Codecache is for compiled code, so it doesn't necessarily correlate to the original program's source code size. You can have the same methods inlined in many places, load the same classes in multiple class loaders (which means they are separate classes to the JVM), generate code at runtime, etc. For example, Presto is a SQL query engine that generates code for each query (a SQL query is effectively a program), so it…

> You can have the same methods inlined in many places

Isn't the JVM more conservative about inlining already inlined methods? I can't find a cite right now, but I swear I've seen this when inspecting the compiler output.

Re: JRE 8 needs more codecache than before

#24
post #21

Earlier quoted context omitted.

Author here. We know 128MB codecache was not enough and 256MB was sufficient. I think we could have gotten by with less, e.g. 200MB, but we stopped experimenting once we found a value that worked. We don't have a complete understanding of why this app uses so much more codecache than other apps we've switched to Java 8. Now that we expose the codecache size in Datadog, I may try plotting code size vs codecache size f…

Datadog employee here, you don't need to run your own collector to collect codecache usage. As it's exposed through JMX, the JMX collector can collect it http://docs.datadoghq.com/integrations/java/ . It doesn't by default though, so you'll need to configure it to collect the metrics from the "java.lang:name=Code Cache,type=MemoryPool" bean. We should add that in our default configuration.

If it's exposed through JMX, would it also be visible via something like jvisualvm?

Re: JRE 8 needs more codecache than before

#25
post #8
post #4

How much Java source code does it take to need 256MB of codecache? The author says they're using a service architecture where each transaction uses about 20 services. There's no indication of why their program is so huge.

Codecache is for compiled code, so it doesn't necessarily correlate to the original program's source code size. You can have the same methods inlined in many places, load the same classes in multiple class loaders (which means they are separate classes to the JVM), generate code at runtime, etc. For example, Presto is a SQL query engine that generates code for each query (a SQL query is effectively a program), so it…

Now that's something to look for. If something is generating code for each transaction, and that code shares a cache with other, more permanent code, cache thrashing is possible. If the cache management favors new code over old code, old code is likely to be pushed out as the cache fills up with query code. Then the old code gets recompiled the next time it's needed. Could that be why so much time is being spent in the JIT compiler?

Re: JRE 8 needs more codecache than before

#26

If the JVM has one bytecode compiler that it uses only during startup and another that it used the rest of the time, shouldn't it dump the bytecode generated by the first compiler from the cache at the point when it switches to the second compiler?

The article's wording is a bit misleading here. The first-tier and second-tier compilers are always available throughout the entire lifetime of the program. The first-tier compiler performs very few optimizations, but compiles very quickly. It is a simple and literal compiler -- most direct translation of byte code to machine code. It's meant to be a quick win to get out of interpreted mode, which is vastly slower. The second-tier compiler is slower, but also takes advantage of the data collected during runtime profiling to make optimizations. Basically, there's a trade-off between the time it takes to run the second-tier compiler and the time it will save. By comparison, the first-tier compiler is almost always a win over interpreted code, even if the code is only run a small number of times.

Now, sometimes optimizations can be "wrong", in the sense that something new has happened that invalidates an assumption used during second-tier compilation. Here's a real-world example: I have an interface and only one loaded class that implements that interface. The second-tier compiler will use this information to basically do this:

    function doStuff(MyInterface a) {
        if (a.getClass() != MyClass.class)
            deoptimize();

        // Do everything from here on assuming
        // that a is an instance of MyClass.
        // This includes inlining simple getter
        // methods to pure field accesses, etc.
    }
Now, when a second class that implements `MyInterface` is loaded and makes it to that function, it will hit the `deoptimize` branch and go back to first-tier or even interpreted mode. Eventually the function will be recompiled by both tiers with the new assumption -- two implementing classes.

So, in the case of deoptimization, it can be a win to keep the first-tier code to fall-back to.

Re: JRE 8 needs more codecache than before

#27
-XX:-TieredCompilation is the magic option to disable tiered compilation.

Beginning with Java 8, instead of having the VM to magically choose between using the client JIT (c1: think V8) or the server JIT (c2: think gcc -O2), the default configuration is to run in so called "tiered mode", first starts with the interpreter (as usual) then c1 (here keep the profile info) then c2. Because the code is compiled twice, you need a twice bigger code cache.

From my own experience, tiered compilation is nice when you run something interactive like an IDE (IntelliJ IDEA) and useless when you run a server app. That's said i've never had to have a 250MB code cache.

Re: JRE 8 needs more codecache than before

#28

If the JVM has one bytecode compiler that it uses only during startup and another that it used the rest of the time, shouldn't it dump the bytecode generated by the first compiler from the cache at the point when it switches to the second compiler?

I think you meant the machine code. The Java compiler produces bytecode from Java source. The C1 and C2 bytecode compilers in the JVM convert bytecode to machine code. Yes, I agree if C2 recompiles something C1 already compiled, the C1-compiled machine code should be freed from the codecache.

It will be freed but when c2 has emitted the new machine code, you can still have code on the stack of the user threads that use the code compiled by c1. When no more threads will use the c1 generated code, it will be swept from the code cache.

Re: JRE 8 needs more codecache than before

#29

If the JVM has one bytecode compiler that it uses only during startup and another that it used the rest of the time, shouldn't it dump the bytecode generated by the first compiler from the cache at the point when it switches to the second compiler?

The article's wording is a bit misleading here. The first-tier and second-tier compilers are always available throughout the entire lifetime of the program. The first-tier compiler performs very few optimizations, but compiles very quickly. It is a simple and literal compiler -- most direct translation of byte code to machine code. It's meant to be a quick win to get out of interpreted mode, which is vastly slower. T…

yes that's the idea ! but your example is wrong because c1 never compile a branch that was not executed before.

Re: JRE 8 needs more codecache than before

#30
post #8

Earlier quoted context omitted.

Codecache is for compiled code, so it doesn't necessarily correlate to the original program's source code size. You can have the same methods inlined in many places, load the same classes in multiple class loaders (which means they are separate classes to the JVM), generate code at runtime, etc. For example, Presto is a SQL query engine that generates code for each query (a SQL query is effectively a program), so it…

> You can have the same methods inlined in many places Isn't the JVM more conservative about inlining already inlined methods? I can't find a cite right now, but I swear I've seen this when inspecting the compiler output.

yes, if the method was already compiled into a big or medium size method (in term of assembly code). JITs will not try to inline it again otherwise you will have too much code duplication and nobody want too many cache misses from the instruction cache.
Post reply on HN