This question already has answers here:
Performance difference between post- and pre- increment operators? [closed]
(2 answers)
Closed 7 years ago.
Is there in JAVA a performance difference between i++; and i--;
I'm not able to evaluate bytecode for this, and I think that simple benchmarks are not reliable because of dependence on a specific algorithm.
im not able to evaluate bytecode
Besides the duplicate which I linked and which shows some general things to consider when asking performance related questions:
Given the following sample code (System.err.println is essentially necessary so that the compiler does not optimize away the unused variable):
public class IncDec {
public static void main(String[] args) {
int i = 5;
i++;
System.err.println(i);
i--;
System.err.println(i);
}
}
Disassembled code:
> javap -c IncDec
Compiled from "IncDec.java"
public class IncDec {
public IncDec();
Code:
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_5
1: istore_1 // int i = 5
2: iinc 1, 1 // i++
5: getstatic #16 // Field java/lang/System.err:Ljava/io/PrintStream;
8: iload_1
9: invokevirtual #22 // Method java/io/PrintStream.println:(I)V
12: iinc 1, -1 // i--
15: getstatic #16 // Field java/lang/System.err:Ljava/io/PrintStream;
18: iload_1
19: invokevirtual #22 // Method java/io/PrintStream.println:(I)V
22: return
}
So, no, there is no performance difference in this particular case on a bytecode level - both statements are compiled to the same bytecode instruction.
The JIT compiler could be free to do any additional optimization though.
In Java, there isn't a difference in speed between the two. At the most basic level, subtraction is simply addition. That is, taking the 2's complement and adding it.
Related
This question already has answers here:
Declaring variables inside or outside of a loop
(20 answers)
Closed 5 years ago.
First 2 examples:
1)
MyClass myClass;
for (int i=0; i<arrayList.size(); i++) {
myClass = arrayList.get(i);
...
}
2)
for (int i=0; i<arrayList.size(); i++) {
MyClass myClass = arrayList.get(i);
...
}
In the first example the reference variable myClass is created only once. But what about in the second example, is it created only once, or once for each iteration? My thought is perhaps the compiler optimizes this, I don't know.
I tried to answer this question by coding an example, but couldn't figure it out. How can it be proven via code?
Note: I realize example 2 is better style since myClass isn't known outside of the for loop, and it's scope is kept to a minimum. I also have searched here but haven't found a definitive answer to this exact question (usually it's a question of "which is preferred?".) I also assume that if the myClass reference is created each iteration it isn't a big performance issue.
Edit: Again, I am not asking which is better coding style. Also, I wonder if it can be deduced/proven via code. I tried to generate and compare the bytecode, but I am not familiar with bytecode and what was generated was not an exact match.
When you declare a variable, you don't "create" anything. Variables are just a convenient name to help you remember where you put some result, and allow you to control where that result can be used, and associate some type information with that result; but once you compile the code, they no longer exist.
Compare the bytecode (*):
void outside(int i, List<?> list) {
Object obj;
for (i = 0; i < list.size(); i++) {
obj = list.get(i);
}
}
void inside(int i, List<?> list) {
for (i = 0; i < list.size(); i++) {
Object obj = list.get(i);
}
}
Decompiles to:
void outside(int, java.util.List<?>);
Code:
0: iconst_0
1: istore_1
2: iload_1
3: aload_2
4: invokeinterface #2, 1 // InterfaceMethod java/util/List.size:()I
9: if_icmpge 26
12: aload_2
13: iload_1
14: invokeinterface #3, 2 // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
19: astore_3
20: iinc 1, 1
23: goto 2
26: return
void inside(int, java.util.List<?>);
Code:
0: iconst_0
1: istore_1
2: iload_1
3: aload_2
4: invokeinterface #2, 1 // InterfaceMethod java/util/List.size:()I
9: if_icmpge 26
12: aload_2
13: iload_1
14: invokeinterface #3, 2 // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
19: astore_3
20: iinc 1, 1
23: goto 2
26: return
The two are identical. Use the one which is most readable.
(*) I've declared the loop variable i as a parameter, in order to avoid any differences in the generated bytecode caused by the Object being declared before or after i. The only difference this makes to the bytecode is in the aload_N/iload_N/astore_N/istore_N instructions - the N is different because the variables are stored in different "slots". This is not a significant difference.
Here is a simple question about Java compile optimisation.
Is
final int CONSTANT_NUMBER="Foo Bar".length();
equal to
final int CONSTANT_NUMBER=7;
on compiling code or generally in performance aspect?
No the java compiler doesn't evaluate "Foo Bar".length() at compile time.
Consider these classes
public class ConstantCheck {
final int CONSTANT_NUMBER = "Foo Bar".length();
}
and
public class ConstantCheck {
final int CONSTANT_NUMBER = 7;
}
Using javap -v on the compiled .class file you can see, that the .length() call is kept:
The former results in
...
final int CONSTANT_NUMBER;
descriptor: I
flags: ACC_FINAL
public text.ConstantCheck();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: ldc #2 // String Foo Bar
7: invokevirtual #3 // Method java/lang/String.length:()I
10: putfield #4 // Field CONSTANT_NUMBER:I
13: return
...
the latter in
...
final int CONSTANT_NUMBER;
descriptor: I
flags: ACC_FINAL
ConstantValue: int 7
public text.ConstantCheck();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: bipush 7
7: putfield #2 // Field CONSTANT_NUMBER:I
10: return
....
In the first case the .length call is present
7: invokevirtual #3 // Method java/lang/String.length:()I
in the second case it's just a constant that is written to the field
5: bipush 7
7: putfield #2 // Field CONSTANT_NUMBER:I
From compiling, definitely second is going to be a little faster, as it first has a method call. However, machines these days are way too fast for this to be noticeable or significant.
For performance - Modern compilers should be smart to see that "Foo Bar" is a constant and should replace the expression to length. If however, you change the line to be a variable, then you may be able to fool the compiler to call the method every time, there by making 1st slightly faster if run in a big loop.
I tested this by making them run in a big loop and second method gave slightly better performance. Guess my compiler isn't smart enough to replace the method call with a constant.
So short answer , performance wise, direct int is better than method call on my machine, but it may differ on a different compiler.
Why does Java have an IINC bytecode instruction?
There is already an IADD bytecode instruction that can be used to accomplish the same.
So why does IINC exist?
Only the original designers of Java can answer why they made particular design decisions. However, we can speculate:
IINC does not let you do anything that can't already be accomplished by a ILOAD/SIPUSH/IADD/ISTORE combo. The difference is that IINC is a single instruction, which only takes 3 or 6 bytes, while the 4 instruction sequence is obviously longer. So IINC slightly reduces the size of bytecode that uses it.
Apart from that, early versions of Java used an interpreter, where every instruction has overhead during execution. In this case, using a single IINC instruction could be faster than the equivalent alternative bytecode sequence. Note that JITting has made this largely irrelevant, but IINC dates back to the original version of Java.
As already pointed out a single iinc instruction is shorter than the a iload, sipush, iadd, istore sequence. There is also evidence, that performing a common-case code size reduction was an important motivation.
There are specialized instructions for dealing with the first four local variables, e.g. aload_0 does the same as aload 0 and it will be used often for loading the this reference on the operand stack. There’s an ldc instruction being able to refer to one of the first 255 constant pool items whereas all of them could be handled by ldc_w, branch instructions use two bytes for offsets, so only overly large methods have to resort to goto_w, and iconst_n instructions for -1 to 5 exist despite these all could be handled by bipush which supports values which all also could all be handled by sipush, which could be superseded by ldc.
So asymmetric instructions are the norm. In typical applications, there are a lot of small methods with only a few local variables and smaller numbers are more common than larger numbers. iinc is a direct equivalent to stand-alone i++ or i+=smallConstantNumber expressions (applied to local variables) which often occur within loops. By being able to express common code idioms in more compact code without loosing the ability to express all code, you’ll get great savings in overall code size.
As also already pointed out, there is only a slight opportunity for faster execution in interpreted executions which is irrelevant for compiled/optimized code execution.
Looking at this table, there are a couple important differences.
iinc: increment local variable #index by signed byte const
iinc uses a register instead of the stack.
iinc can only increment by a signed byte value. If you want to add [-128,127] to an integer, then you could use iinc, but as soon as you want to add a number outside that range you would need to use isub, iadd, or multiple iinc instructions.
E1:
TL;DR
I was basically right, except that the limit is signed short values (16 bits [-32768,32767]). There's a wide bytecode instruction which modifies iinc (and a couple other instructions) to use 16 bit numbers instead of 8 bit numbers.
Additionally, consider adding two variables together. If one of the variables is not constant, the compiler will never be able to inline its value to bytecode, so it cannot use iinc; it will have to use iadd.
package SO37056714;
public class IntegerIncrementTest {
public static void main(String[] args) {
int i = 1;
i += 5;
}
}
I'm going to be experimenting with the above piece of code. As it is, is uses iinc, as expected.
$ javap -c IntegerIncrementTest.class
Compiled from "IntegerIncrementTest.java"
public class SO37056714.IntegerIncrementTest {
public SO37056714.IntegerIncrementTest();
Code:
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_1
1: istore_1
2: iinc 1, 5
5: return
}
i += 127 uses iinc as expected.
$ javap -c IntegerIncrementTest.class
Compiled from "IntegerIncrementTest.java"
public class SO37056714.IntegerIncrementTest {
public SO37056714.IntegerIncrementTest();
Code:
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_1
1: istore_1
2: iinc 1, 127
5: return
}
i += 128 does not use iinc anymore, but instead iinc_w:
$ javap -c IntegerIncrementTest.class
Compiled from "IntegerIncrementTest.java"
public class SO37056714.IntegerIncrementTest {
public SO37056714.IntegerIncrementTest();
Code:
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_1
1: istore_1
2: iinc_w 1, 128
8: return
}
i -= 601 also uses iinc_w:
$ javap -c IntegerIncrementTest.class
Compiled from "IntegerIncrementTest.java"
public class SO37056714.IntegerIncrementTest {
public SO37056714.IntegerIncrementTest();
Code:
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_1
1: istore_1
2: iinc_w 1, -601
8: return
}
The _w suffix refers to the wide bytecode, which allows for constants up to 16 bits ([-32768, 32767]).
If we try i += 32768, we will see what I predicted above:
$ javap -c IntegerIncrementTest.class
Compiled from "IntegerIncrementTest.java"
public class SO37056714.IntegerIncrementTest {
public SO37056714.IntegerIncrementTest();
Code:
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_1
1: istore_1
2: iload_1
3: ldc #16 // int 32768
5: iadd
6: istore_1
7: return
}
Additionally, consider the case where we are adding another variable to i (i += c). The compiler doesn't know if c is constant or not, so it cannot inline c's value to bytecode. It will use iadd for this case too:
int i = 1;
byte c = 3;
i += c;
$ javap -c IntegerIncrementTest.class
Compiled from "IntegerIncrementTest.java"
public class SO37056714.IntegerIncrementTest {
public SO37056714.IntegerIncrementTest();
Code:
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_1
1: istore_1
2: iconst_3
3: istore_2
4: iload_1
5: iload_2
6: iadd
7: istore_1
8: return
}
I'm going to make some investigations about dividing large arrays/matrix computations among multiple threads. But I need to know the relative time complexity of Java basic operations.
For instance:
int a = 23498234;
int b = -34234;
int[] array = new int[10000];
int c = a + b; // 1
int c = array[234]; // 2
String 1 (summary of two integers) is 10+ times faster than string 2 (memory access)
or (i & 1) == 0 is 10+ faster than i % 2 == 0.
Question: Can you supppose time relations between next operations:
+, * and / operands (suppose on Integer type)
memory access
starting new thread
For performance timing, there are many confounding factors. Rather than try to get exact timings, it's better to understand what's going on and measure what you can.
The time utility will give you detailed stats on an executable, but keep in mind you're timing the JVM which is running the code, not just your code.
You might try the javap disassembler too -- ultimately you'll want to know how your individual operations break down into java bytecode, and the amount of time it takes to execute certain key bits.
Example source code:
public class T {
public static void main(String [] args) {
int x=2;
int y=3;
int z=x+y;
System.out.println(""+x);
}
}
Compiled, then disassembled:
$ javap -c T
Compiled from "T.java"
public class T {
public T();
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_2
1: istore_1
2: iconst_3
3: istore_2
4: iload_1
5: iload_2
6: iadd
7: istore_3
8: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
11: new #3 // class java/lang/StringBuilder
14: dup
15: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
18: ldc #5 // String
20: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
23: iload_1
24: invokevirtual #7 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
27: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
30: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
33: return
}
Look at code #6 - that's where the actual addition is happening.
One thing you need to establish is how the operations you're interested in turn into bytecode.
Within the JVM itself, you can use System.getCurrentTimeMillis() as a way of timing, but it won't give you sub-ms resolution. You can also use System.nanoTime(); to get higher precision time, (in the sense that it's sub-ms resolution) but it's less accurate.
I'm trying to understand 'native code generation and execution' part of Java JITC, but having a hard time visualizing exactly what happens. E.g. say I have the following class:
class Foo
{
private int x;
public void incX()
{
x++;
}
}
javac generates the following byte code for the method:
public void incX();
Code:
Stack=3, Locals=1, Args_size=1
0: aload_0
1: dup
2: getfield #17; //Field x:I
5: iconst_1
6: iadd
7: putfield #17; //Field x:I
10: return
LineNumberTable:
line 33: 0
line 34: 10
LocalVariableTable:
Start Length Slot Name Signature
0 11 0 this LFoo;
When JITC converts this into native code, what exactly happens? And how is this native code executed by JVM?
When the method gets called sufficiently often to pass the JVM's compilation threshold, the JIT compiles the bytecode into native code, and sets it up so that calls to the function go directly to the natively compiled method.