تاشو ثابت در JVM: چگونه کامپایلر کد شما را سریعتر می کند!

سلام توسعه دهندگان جاوا. به مقاله جدید من خوش آمدید موضوع امروز تاشو ثابت است.
تاشو ثابت چیست؟
تاشو ثابت یک تکنیک بهینه سازی مهم است که توسط دستگاه مجازی جاوا (JVM) و کامپایلر برای تقویت عملکرد استفاده می شود. این نه تنها در JVM مورد استفاده قرار می گیرد ، بلکه در کامپایلرهای زبانهای مدرن نیز مورد استفاده قرار می گیرد.
این تکنیک با ارزیابی عبارات ثابت در زمان کامپایل و نه زمان اجرا ، محاسبات اضافی را از بین می برد. این منجر به اجرای سریعتر و کاهش اندازه بایت می شود.
به عنوان مثال ، کد جاوا زیر را در نظر بگیرید:
public class ConstantFoldingExample {
public static void main(String[] args) {
int x = 5 + 10;
System.out.println(x);
}
}
کامپایلر جاوا آن را تشخیص می دهد 5 + 10
یک بیان ثابت است و آن را ساده می کند 15
بشر در نتیجه ، کد بایت کامپایل شده شامل یک عمل اضافی نیست بلکه مستقیماً بارهای می شود 15
به متغیر
بیایید با استفاده از ابزار خط فرمان javap ، کد bytecode را کشف کنیم. خطوط زیر را در ترمینال خود اجرا کنید.
$ javac ConstantFoldingExample.java
$ javap -c ConstantFoldingExample
بایت کد کامپایل شده ممکن است به شرح زیر باشد:
0: bipush 15 // Push the constant value 15 onto the stack
2: istore_1 // Store it in variable x
3: getstatic java/lang/System/out Ljava/io/PrintStream;
6: iload_1 // Load x (which is 15)
7: invokevirtual java/io/PrintStream.println (I)V
10: return
آیا تاشو ثابت فقط در عملیات حسابی رخ می دهد؟
پاسخ کوتاه خیر. در موارد زیر رخ می دهد.
- عملیات حسابی (علاوه بر این ، تفریق ، ضرب و غیره)
- هماهنگی رشته ای
- بولی
ما قبلاً دیدیم که چگونه تاشو ثابت در عملیات حسابی رخ می دهد ، بیایید دو مورد دیگر را ببینیم.
هماهنگی رشته ای
کد جاوا را دنبال کنید
public class ConstantFoldingWithStrings {
public static void main(String... args) {
String message = "Hello" + "World";
System.out.println("Message: " + message);
}
}
برای به دست آوردن کد بایت ، همان اقداماتی را که در کارنامه انجام داده اید انجام دهید.
0: ldc #7 // String HelloWorld
خروجی برای سادگی کوتاه می شود. نیازی به گفتن چیزی نیست ، از نتیجه آشکار است.
تاشو بولی
تاشو بولی ممکن است شما را گیج کند ، اما ما هر دو گزینه ممکن را خواهیم دید ( false
وت true
مورد)
true
مورد:
public class ConstantFoldingWithBooleans {
public static void main(String... args) {
boolean isBool = 3 < 5 && 6 < 8; // true
System.out.println("Bool: " + isBool);
}
}
در اینجا کد تولید شده ایجاد شده است:
0: iconst_1
1: istore_1
iconst_1
Opcode به معنی “فشار مستقیم است 1
و در 1
معقول بودن true
بشر
بیایید ببینیم false
مورد:
public class ConstantFoldingWithBooleans {
public static void main(String... args) {
boolean isBool = 3 > 5 && 6 < 8; // false
System.out.println("Bool: " + isBool);
}
}
BYTECODE تولید شده:
0: iconst_0
1: istore_1
iconst_0
Opcode به معنای فشار است int
ثابت 0
و در 0
معقول بودن false
بشر
نمونه حیله گر
بیشتر اوقات ، ما با تعبیه ثابت به طور مستقیم در عبارات ، کد را به این روش نمی نویسیم. درعوض ، ما آنها را ذخیره می کنیم متغیرها برای خوانایی بهتر و قابلیت حفظ. با این حال ، تاشو ثابت هنگامی اتفاق می افتد که متغیرها به عنوان اعلام شوند final
بشر
مثال زیر را در نظر بگیرید
public class ConstantFolding {
public static void main(String... args) {
final int campaignPoints = 2000;
final int rate = 2;
int amount = getTransactionAmount() * campaignPoints * rate;
System.out.println("Amount: " + amount);
}
public static int getTransactionAmount() {
return 3000;
}
}
در مثال بالا ، اگر کلمه کلیدی نهایی را در مقابل متغیرها ننوشتیم ، تاشو ثابت در زمان کامپایل اتفاق نمی افتد. بیایید ببینیم چه چیزی به عنوان کد bytecode تولید می شود.
0: invokestatic #7 // Method getTransactionAmount:()I
3: sipush 2000
6: imul
7: iconst_2
8: imul
9: istore_1
تاشو ثابت بدون توجه به final
کلمات کلیدی چرا؟
این ترفند در پشت معادله پنهان است.
int amount = getTransactionAmount() * campaignPoints * rate;
جاوا عملیات حسابی را از چپ به راست محاسبه می کند. بنابراین اولین عمل ( getTransactionAmount()
) نیست final
بشر به همین دلیل است که تاشو ثابت رخ نداد.
اگر متغیرهای ثابت را با پرانتز ببندیم یا موقعیت های Operands را تغییر دهیم ، تاشو ثابت رخ خواهد داد.
int amount = getTransactionAmount() * (campaignPoints * rate);
// or
int amount = campaignPoints * rate * getTransactionAmount();
// or
final int multiplier = campaignPoints * rate;
int amount = multiplier * getTransactionAmount();
می توانید یکی از موارد فوق را انتخاب کنید. در اینجا نسخه bytected تولید شده است
0: invokestatic #7 // Method getTransactionAmount:()I
3: sipush 4000 // 2000 * 2 = 4000
6: imul
7: istore_1
این بار تاشو ثابت رخ داد.
مزایای تاشو ثابت
- با از بین بردن محاسبات اضافی ، عملکرد را بهبود می بخشد.
- اندازه بایت را کاهش می دهد.
- JVM سریعتر کد بهینه شده را اجرا می کند
inconcclusion
تاشو ثابت یک بهینه سازی قدرتمند است که با پیش بینی عبارات ثابت باعث افزایش کارایی برنامه جاوا می شود.
مثل همیشه ، کد منبع در GitHub موجود است.