5 ms·
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
by bobbyi_settv 10y ago
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?
- sambe 10y agoCode is sometimes un-optimised, presumably the best option is to go back to lightly-compiled.
- billsmithaustin 10y agoI 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.
- __-X-__ 10y agoIt 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.
- jdmichal 10y agoThe 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.
- __-X-__ 10y agoyes that's the idea ! but your example is wrong because c1 never compile a branch that was not executed before.