6

I'm curious how are the static final fields treated by the JVM. I saw a similar question here but it's not what I'm looking for. Let's consider such example:

public class TestClassX {
   public final int CODE_A = 132;
   public final int CODE_B = 948;
   public final int CODE_C = 288;
   // some other code
}

public class TestClassY {
   public static final int CODE_A = 132;
   public static final int CODE_B = 948;
   public static final int CODE_C = 288;
   // some other code
}

In TestClassX fields, as they are final and cannot be modified, have the same values in all instances of the TestClassX class. Of course I cannot write TestClassX.CODE_A but I can say, that these values are actually common for all instances - I'm sure, that each instance has a CODE_A field with the value 132.

In the TestClassY I can use the syntax TestClassY.CODE_A, but at a first sight it's only easier for a developer who sees "Oh, those values are common for all instances".

My main question: I guess that JVM, in case of TestClassX, doesn't use any extra memory for final fields each time a new instance is created. Does it? Does JVM make any optimization in this case and what kind of optimization it is?

Extra question 1) I'm also sure that I'm missing something very important here which is the cause of my doubts. What's that?

Extra question 2) Btw. How can I take a look at how my Java source code looks like after the JVM optimization (so I can use in in the future ;))? Does any IDE support such a functionality? IntelliJ for example? I would like simply to see how JVM treats my TestClassX and TestClassY.

Community
  • 1
  • 1
radekEm
  • 4,617
  • 6
  • 32
  • 45
  • related - javac always inlines constant instance variables, probably a bug:) - https://groups.google.com/forum/#!topic/java-lang-fans/AyS3UqX4lj4 – ZhongYu Sep 11 '15 at 17:08
  • 2) The JVM's optimizations aren't done in a way that lends itself to being expressed as Java source. Compilers optimize an internal representation of what the code *does*. source->source optimizers usually only exist for languages that have to be compiled every time they're used (e.g. javascript). Your actual goal here should be covered by looking at the Java byte-code, or the asm resulting from JIT-compiling for a specific CPU. (Or traditional ahead-of-time compiling for Java implementations like gcj`.) – Peter Cordes Sep 12 '15 at 23:30

2 Answers2

8
  • Non-static fields are always present in the instances. They do not save memory.
  • In general JVM does not optimize non-static fields. Even if they are final they can be still set to different value using reflection or during deserialization.
  • There is an experimental VM option -XX:+TrustFinalNonStaticFields (off by default) which tells JVM to optimize access to such fields, i.e. treat them as constants and eliminate field loads.
  • There is a -XX:+PrintAssembly VM option to dump JIT-compiled code.
apangin
  • 92,924
  • 10
  • 193
  • 247
  • Thanks that you mentioned about reflection and deserialization. And for TrustFinalNonStaticFields option - I didn't know! ... ^ – radekEm Sep 11 '15 at 12:47
1

For the first part of your question, maybe this answer can help you.

For the second part you could see the generated assembly (as stated in this answer) by adding -XX:+PrintOptoAssembly flag when you run/compile your code.

I should also add that the assembly code given to you is not the real opcode generated by the jvm, but the code needed to be run under your actual architecture.

Hope this helps!

Community
  • 1
  • 1
underscore_nico
  • 139
  • 1
  • 2
  • 14