Reputation: 307
I have a question about how java deals with unused variables.
Let's say that i have the following code:
int notUsedVariable = aMethodThatExecutesSomethingImportantAndReturnsInt(someParameter);
Then I never use notUsedVariable in the code. Will that variable actually be stored, or java is smart enough to ignore the variable when compiling?
Thanks!
Upvotes: 2
Views: 2576
Reputation: 25623
My observation has been that javac may omit the store operations of unused variables if:
final
and are initialized in the declaration;-g:vars
)If you compile with -g:vars
, javac will keep the variables loads and stores in tact for debugging purposes. It does not appear to consider non-final variables as eligible for removal.
Test for yourself. My results with JDK 7 are below. The results were identical with a JDK 8 EAP.
Input:
class MyTest {
public static void main(String... args) {
int a = 1;
}
}
Output:
public static void main(java.lang.String... p0);
Flags: PUBLIC, STATIC, VARARGS
Code:
stack=1, locals=2, arguments=1
0: iconst_1
1: istore_1
2: return
Input:
class MyTest {
public static void main(String... args) {
final int a = 1;
}
}
Output:
public static void main(java.lang.String... p0);
Flags: PUBLIC, STATIC, VARARGS
Code:
stack=1, locals=2, arguments=1
0: return
As others have said, in either case I would expect the JIT optimizer to omit any unnecessary store operations.
Upvotes: 5
Reputation: 1962
It will be stored based upon the scope of the variable that when the scope ends, garbage collection will clean up the memory used by the variable.
I edited once of my Test classes for a class variable and local variable and then used Eclipse to inspect the class file. (Eclipse complains that the variable is never used.)
// Compiled from UserLoadTest.java (version 1.6 : 50.0, super bit)
public class org.dev.user.UserLoadTest extends org.test.BaseTestCase {
// Field descriptor #6 I
public int myVariable;
...we can see that the class file sees this
@org.junit.Test
public void testBasicUserLoad() throws java.io.IOException, org.custommonkey.xmlunit.exceptions.XpathException;
0 aload_0 [this]
1 ldc <String "user_01.xml"> [24]
...
org.custommonkey.xmlunit.XMLAssert.assertXpathEvaluatesTo(java.lang.String, java.lang.String, org.w3c.dom.Document) : void [85]
223 aload_2 [reloaded]
224 invokevirtual org.testHarness.Result.getDocument() : org.dom4j.dom.DOMDocument [81]
227 astore_3 [d]
228 return
line 224 is a simple declaration of a variable using
Document d = reloaded.getDocument();
This does nothing with d
but the class file recognizes that the variable was created.
Upvotes: 0
Reputation: 49181
Let's compile an example
public class Test {
public static void main(String... args) {
int a = 1;
}
}
We get
public class Test {
public Test();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String...);
Code:
0: iconst_1 // push integer 1 on stack
1: istore_1 // pop integer from stack, store it in local variable 1
2: return
}
We can see that local variable was not removed. It was stored.
Please remember that at the time of execution optimizations may happen.
Upvotes: 2
Reputation: 359816
If you're concerned just about the static compilation step, and not the JIT, this is simple to check by comparing the bytecode generated from two slightly different classes, using javap
:
class WithLocalVar {
private static int methodWithSideEffect() {
System.out.println();
return 42;
}
public static void main(String[] args) {
int result = methodWithSideEffect();
}
}
class WithoutLocalVar {
private static int methodWithSideEffect() {
System.out.println();
return 42;
}
public static void main(String[] args) {
methodWithSideEffect();
}
}
✗ javac With*
✗ javap -c WithLocalVar
Compiled from "WithLocalVar.java"
class WithLocalVar extends java.lang.Object{
WithLocalVar();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: invokestatic #4; //Method methodWithSideEffect:()I
3: istore_1
4: return
}
✗ javap -c WithoutLocalVar
Compiled from "WithoutLocalVar.java"
class WithoutLocalVar extends java.lang.Object{
WithoutLocalVar();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: invokestatic #4; //Method methodWithSideEffect:()I
3: pop
4: return
}
Therefore, no, the compiler won't optimize away the istore_1
. The JIT is another story...
Upvotes: 2
Reputation: 328608
It depends.
If notUsedVariable
is a local variable, the assignment will probably be ignored by the JIT compiler (but we are talking about one register read/write, i.e. sub-nanosecond stuff on modern desktop processors). As demonstrated by MattBall the bytecode will keep the assignment.
If notUsedVariable
is a member of the class, the result will need to be stored as the field might be accessed later on and it would probably be impossible for the compiler to prove otherwise (a new class could be loaded that does not exist yet for example).
Upvotes: 3
Reputation: 8531
javac does not perform many optimizations. The JIT, on the other hand, does
Check out http://www.ibm.com/developerworks/ibm/library/it-haggar_bytecode/
Here is a qoute.
More importantly, the javac compiler does not perform simple optimizations like loop unrolling, algebraic simplification, strength reduction, and others. To get these benefits and other simple optimizations, the programmer must perform them on the Java source code and not rely on the javac compiler to perform them.
There is also another thread going into more detail about this. Optimization by Java Compiler
Upvotes: 2