โปรดข้ามไปที่คำตอบที่อัพเดต ...
สำหรับผู้ที่สนใจเกี่ยวกับประสิทธิภาพการทำงานจะออก System.out และ จำกัด การวนรอบเป็น 1 ไบต์ การใช้ double (test 1/2) และใช้ String (3/4) เวลาที่ผ่านไปเป็นมิลลิวินาทีจะได้รับด้านล่างด้วย Windows 7 Professional 64 บิตและ JDK-1.7.0_21 Bytecodes (ที่ให้ไว้ด้านล่างสำหรับ test1 และ test2) นั้นไม่เหมือนกัน ฉันขี้เกียจเกินไปที่จะทดสอบกับวัตถุที่ไม่แน่นอนและค่อนข้างซับซ้อน
สอง
ทดสอบ 1: 2710 msecs
ทดสอบ 2: 2790 มิลลิวินาที
String (เพียงแทนที่ double ด้วย string ในการทดสอบ)
ทดสอบ 3: 1200 msecs
ใช้เวลาทดสอบ 4: 3000 มิลลิวินาที
รวบรวมและรับ bytecode
javac.exe LocalTest1.java
javap.exe -c LocalTest1 > LocalTest1.bc
public class LocalTest1 {
public static void main(String[] args) throws Exception {
long start = System.currentTimeMillis();
double test;
for (double i = 0; i < 1000000000; i++) {
test = i;
}
long finish = System.currentTimeMillis();
System.out.println("Test1 Took: " + (finish - start) + " msecs");
}
}
public class LocalTest2 {
public static void main(String[] args) throws Exception {
long start = System.currentTimeMillis();
for (double i = 0; i < 1000000000; i++) {
double test = i;
}
long finish = System.currentTimeMillis();
System.out.println("Test1 Took: " + (finish - start) + " msecs");
}
}
Compiled from "LocalTest1.java"
public class LocalTest1 {
public LocalTest1();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]) throws java.lang.Exception;
Code:
0: invokestatic #2 // Method java/lang/System.currentTimeMillis:()J
3: lstore_1
4: dconst_0
5: dstore 5
7: dload 5
9: ldc2_w #3 // double 1.0E9d
12: dcmpg
13: ifge 28
16: dload 5
18: dstore_3
19: dload 5
21: dconst_1
22: dadd
23: dstore 5
25: goto 7
28: invokestatic #2 // Method java/lang/System.currentTimeMillis:()J
31: lstore 5
33: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
36: new #6 // class java/lang/StringBuilder
39: dup
40: invokespecial #7 // Method java/lang/StringBuilder."<init>":()V
43: ldc #8 // String Test1 Took:
45: invokevirtual #9 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
48: lload 5
50: lload_1
51: lsub
52: invokevirtual #10 // Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
55: ldc #11 // String msecs
57: invokevirtual #9 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
60: invokevirtual #12 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
63: invokevirtual #13 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
66: return
}
Compiled from "LocalTest2.java"
public class LocalTest2 {
public LocalTest2();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]) throws java.lang.Exception;
Code:
0: invokestatic #2 // Method java/lang/System.currentTimeMillis:()J
3: lstore_1
4: dconst_0
5: dstore_3
6: dload_3
7: ldc2_w #3 // double 1.0E9d
10: dcmpg
11: ifge 24
14: dload_3
15: dstore 5
17: dload_3
18: dconst_1
19: dadd
20: dstore_3
21: goto 6
24: invokestatic #2 // Method java/lang/System.currentTimeMillis:()J
27: lstore_3
28: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
31: new #6 // class java/lang/StringBuilder
34: dup
35: invokespecial #7 // Method java/lang/StringBuilder."<init>":()V
38: ldc #8 // String Test1 Took:
40: invokevirtual #9 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
43: lload_3
44: lload_1
45: lsub
46: invokevirtual #10 // Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;
49: ldc #11 // String msecs
51: invokevirtual #9 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
54: invokevirtual #12 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
57: invokevirtual #13 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
60: return
}
ปรับปรุงคำตอบ
มันไม่ง่ายเลยที่จะเปรียบเทียบประสิทธิภาพกับการเพิ่มประสิทธิภาพ JVM ทั้งหมด อย่างไรก็ตามมันเป็นไปได้ค่อนข้าง การทดสอบที่ดีขึ้นและผลลัพธ์โดยละเอียดใน Google Caliper
- รายละเอียดบางอย่างในบล็อก:คุณควรประกาศตัวแปรภายในลูปหรือก่อนลูปหรือไม่?
- พื้นที่เก็บข้อมูล GitHub: https://github.com/gunduru/jvdt
- ผลการทดสอบสำหรับกรณีที่สองและ 100M วน (และใช่รายละเอียด JVM ทั้งหมด): https://microbenchmarks.appspot.com/runs/b1cef8d1-0e2c-4120-be61-a99faff625b4
- ประกาศก่อนหน้านี้ 1,759.209 ns
- ประกาศภายใน 2,242.308 ns
รหัสการทดสอบบางส่วนสำหรับการประกาศสองครั้ง
สิ่งนี้ไม่เหมือนกับรหัสด้านบน หากคุณเพิ่งเขียนรหัสหุ่นจำลอง JVM ข้ามไปดังนั้นอย่างน้อยคุณต้องกำหนดและส่งคืนบางสิ่งบางอย่าง ขอแนะนำในเอกสารประกอบ Caliper
@Param int size; // Set automatically by framework, provided in the Main
/**
* Variable is declared inside the loop.
*
* @param reps
* @return
*/
public double timeDeclaredInside(int reps) {
/* Dummy variable needed to workaround smart JVM */
double dummy = 0;
/* Test loop */
for (double i = 0; i <= size; i++) {
/* Declaration and assignment */
double test = i;
/* Dummy assignment to fake JVM */
if(i == size) {
dummy = test;
}
}
return dummy;
}
/**
* Variable is declared before the loop.
*
* @param reps
* @return
*/
public double timeDeclaredBefore(int reps) {
/* Dummy variable needed to workaround smart JVM */
double dummy = 0;
/* Actual test variable */
double test = 0;
/* Test loop */
for (double i = 0; i <= size; i++) {
/* Assignment */
test = i;
/* Not actually needed here, but we need consistent performance results */
if(i == size) {
dummy = test;
}
}
return dummy;
}
สรุป: ประกาศก่อนหน้านี้จะระบุประสิทธิภาพที่ดีขึ้น - เล็ก ๆ น้อย ๆ - และมันขัดกับหลักการขอบเขตที่เล็กที่สุด JVM ควรทำสิ่งนี้เพื่อคุณ