←Older revision | Revision as of 05:44, 26 March 2022 | ||
Line 5: | Line 5: | ||
Yet, at the old days when compiler output was directly consumed by hardware CPU and there was no chance to optimize something later, everything had to be done during the compilation. At that time various C++ compilers competed among themselves to produce the fastest code, the most optimized one. The competition had to be quite hard, as often they tried to optimize too much and sometimes even ''overoptimized''. I remember that from time to time I was getting some mysterious error in my program that vanished away as soon as (usually after many hours of debugging) I realized what can be the cause and I disabled some optimization switches. | Yet, at the old days when compiler output was directly consumed by hardware CPU and there was no chance to optimize something later, everything had to be done during the compilation. At that time various C++ compilers competed among themselves to produce the fastest code, the most optimized one. The competition had to be quite hard, as often they tried to optimize too much and sometimes even ''overoptimized''. I remember that from time to time I was getting some mysterious error in my program that vanished away as soon as (usually after many hours of debugging) I realized what can be the cause and I disabled some optimization switches. | ||
- | For a while I believed that problems of this kind cannot happen to [[JavaC]], however I was probably wrong. Recently I needed to prevent an object to be garbage collected from memory and wrote following code: | + | For a while I believed that problems of this kind cannot happen to [[JavaC]], however I was probably wrong. Recently I needed to prevent an object to be [[Garbage Collection|garbage collected]] from memory and wrote following code: |
<source lang="java" snippet="compiler.surprises.intro"/> | <source lang="java" snippet="compiler.surprises.intro"/> | ||
Line 13: | Line 13: | ||
<source lang="java" snippet="compiler.surprises.error"/> | <source lang="java" snippet="compiler.surprises.error"/> | ||
- | So far, so good. This code behaves exactly as expected. It leads to conclusion that if you have a variable defined in a method body, and it has a reference to your object, the object cannot be garbage collected, until the method execution ends. OK, now guess: will the following test succeed or fail? | + | So far, so good. This code behaves exactly as expected. It leads to conclusion that if you have a variable defined in a method body, and it has a reference to your object, the object cannot be [[Garbage Collection|garbage collected]], until the method execution ends. OK, now guess: will the following test succeed or fail? |
<source lang="java" snippet="compiler.surprises.surprise"/> | <source lang="java" snippet="compiler.surprises.surprise"/> | ||
- | To my biggest surprise the reference can really be garbage collected, even there is a local variable pointing to it! This is an example of surprising (''over'')optimization of [[JavaC]] or [[HotSpot]]. It turns out that, in spite of being declared for the whole method, the variable is not used outside of the '''if''' block and as such the [[JavaC]] allocates its space on stack only for the execution of the '''if''' branch. This is quite surprising behaviour. An easy to fix one, yet surprising one: | + | To my biggest surprise the reference can really be [[Garbage Collection|garbage collected]], even there is a local variable pointing to it! This is an example of surprising (''over'')optimization of [[JavaC]] or [[HotSpot]]. It turns out that, in spite of being declared for the whole method, the variable is not used outside of the '''if''' block and as such the [[JavaC]] allocates its space on stack only for the execution of the '''if''' branch. This is quite surprising behaviour. An easy to fix one, yet surprising one: |
<source lang="java" snippet="compiler.surprises.fix"/> | <source lang="java" snippet="compiler.surprises.fix"/> | ||
Line 27: | Line 27: | ||
<source lang="java" snippet="compiler.surprises.fix.final"/> | <source lang="java" snippet="compiler.surprises.fix.final"/> | ||
- | However the same code without '''final''' works as well. It is enough to initialize the variable in both branches of the '''if''' statement to prevent | + | However the same code without '''final''' works as well. It is enough to initialize the variable in both branches of the '''if''' statement to prevent [Garbage Collection]] of the reference held by the ''retValue'' variable: |
<source lang="java" snippet="compiler.surprises.fix.init"/> | <source lang="java" snippet="compiler.surprises.fix.init"/> |