I work on IBM's JIT compiler. We had to do something similar to fix this problem in DirectByteBuffer a few years ago, by adding a call to a magic method called keepAlive. To make this work, we had to teach the JIT to handle this method specially, or else it would have ripped it out, and the fix would have had no effect.
[These are my personal opinions, not those of my employer.]
Also, please note that both Clang and GCC use the same approach, except in their cases the programmer typically does not see the intermediary code (which is LLVM for Clang, and a family of intermediate languages for GCC).
(Also: it's not a stupid approach. Due to the way the JVM loads things, most of the time you don't know that any particular method won't be overridden later by something that does, in fact, have side effects. There are very few optimizations that could actually be done by the Java compiler.)