שיטת ההטבעה ב- JVM

1. הקדמה

במדריך זה, נבדוק מהי שיטת ההטבעה במכונה הווירטואלית של Java ואיך היא עובדת.

נראה גם כיצד לקבל ולקרוא את המידע הקשור להטבעה מה- JVM ומה אנו יכולים לעשות עם מידע זה על מנת לייעל את הקוד שלנו.

2. מהי שיטת ההטבעה?

בעיקרון, הטבעה היא דרך לייעל את קוד המקור המהולל בזמן ריצה על ידי החלפת הקריאות של השיטות המבוצעות לרוב בגופיה.

למרות שיש אוסף מעורב, זה לא מבוצע על ידי המסורתי ג'אוואק מהדר, אך על ידי ה- JVM עצמו. ליתר דיוק, באחריותו של מהדר Just-In-Time (JIT), שהוא חלק מה- JVM; ג'אוואק מייצר רק קוד בתים ומאפשר ל- JIT לעשות את הקסם ולייעל את קוד המקור.

אחת ההשלכות החשובות ביותר של גישה זו היא שאם נחבר את הקוד באמצעות ג'אווה ישנה, ​​אותו הדבר.מעמד הקובץ יהיה מהיר יותר ב- JVM חדש יותר. בדרך זו איננו צריכים לקמפל מחדש את קוד המקור, אלא רק לעדכן את Java.

3. איך JIT עושה את זה?

בעיקרו של דבר, ה מהדר JIT מנסה לשרטט את השיטות שאנו מכנים לעתים קרובות כדי שנוכל להימנע מהתקורה של קריאת שיטה. זה לוקח בחשבון שני דברים כאשר מחליטים אם לשלב שיטה או לא.

ראשית, הוא משתמש בדלפקים כדי לעקוב אחר כמה פעמים אנו קוראים לשיטה. כאשר השיטה נקראת יותר ממספר פעמים ספציפי, היא הופכת "חמה". סף זה מוגדר כברירת מחדל ל 10,000, אך אנו יכולים להגדיר אותו באמצעות דגל JVM במהלך הפעלת Java. אנחנו בהחלט לא רוצים להכניס את הכל למצב מכיוון שזה ייקח זמן רב וייצר קוד בתים ענק.

עלינו לזכור כי ההטבעה תתבצע רק כאשר נגיע למצב יציב. המשמעות היא שנצטרך לחזור על הביצוע מספר פעמים בכדי לספק מספיק מידע על פרופיל עבור מהדר ה- JIT.

יתר על כן, להיות "חם" אינו מבטיח כי השיטה תהיה מודגשת. אם הוא גדול מדי, ה- JIT לא ישים אותו. הגודל המקובל מוגבל על ידי -XX: FreqInlineSize = דגל, המציין את המספר המקסימלי של הוראות קוד-byte להתאמה לשיטה.

עם זאת, מומלץ בחום לא לשנות את ערך ברירת המחדל של דגל זה אלא אם כן אנו בטוחים לחלוטין לדעת מה ההשפעה שהוא יכול להשפיע. ערך ברירת המחדל תלוי בפלטפורמה - עבור לינוקס של 64 סיביות, זה 325.

ה- JIT מוטבע סטָטִי, פְּרָטִי, אוֹ סופי שיטות באופן כללי. ובזמן פּוּמְבֵּי שיטות גם מועמדות להטבעה, לא כל שיטה ציבורית בהכרח תודגם. ה- JVM צריך לקבוע שיש רק יישום יחיד של שיטה כזו. כל תת-מחלקה נוספת תמנע את ההטבעה והביצועים בהכרח יפחתו.

4. מציאת שיטות חמות

אנחנו בוודאי לא רוצים לנחש מה ה- JIT עושה. לכן, אנו זקוקים לאיזו דרך לראות אילו שיטות מונחות או אינן מונחות. אנו יכולים להשיג זאת בקלות ולרשום את כל המידע הזה לפלט הסטנדרטי על ידי הגדרת כמה דגלי JVM נוספים במהלך ההפעלה:

-XX: + PrintCompilation -XX: + UnlockDiagnosticVMOptions -XX: + PrintInlining

הדגל הראשון יירשם כאשר אוסף JIT יתרחש. הדגל השני מאפשר דגלים נוספים כולל -XX: + PrintInlining, אשר ידפיס אילו שיטות מתכווננות ואיפה.

זה יראה לנו את השיטות המוטמעות בצורת עץ. העלים מסומנים ומסומנים באחת מהאפשרויות הבאות:

  • מוטבע (חם) - שיטה זו מסומנת כחמה והיא מוטמעת
  • גדול מדי - השיטה לא חמה, אך גם קוד הביצוע שנוצר שלה גדול מדי, כך שהיא אינה מוטמעת
  • שיטה חמה גדולה מדי - זו שיטה חמה, אך היא אינה מוטמעת מכיוון שקוד התצוגה גדול מדי

עלינו לשים לב לערך השלישי ולנסות לבצע אופטימיזציה של שיטות עם התווית "שיטה חמה גדולה מדי".

באופן כללי, אם אנו מוצאים שיטה חמה עם אמירה מותנית מורכבת מאוד, עלינו לנסות להפריד בין תוכן ה- אם-הצהרה והגדלת הפירוט כך ש- JIT תוכל לבצע אופטימיזציה לקוד. כנ"ל לגבי החלף ו ל-הצהרות לולאה.

אנו יכולים להסיק כי שיטה ידנית בהטבעה היא דבר שאיננו צריכים לעשות על מנת לייעל את הקוד שלנו. ה- JVM עושה את זה ביעילות רבה יותר, ואולי נעשה את הקוד ארוך וקשה למעקב.

4.1. דוגמא

בואו נראה כעת כיצד נוכל לבדוק זאת בפועל. ראשית ניצור מחלקה פשוטה המחשבת את סכום הראשון נ מספרים שלמים חיוביים רצופים:

מחלקה ציבורית ConsecutNumbersSum {private long totalSum; פרטי int totalNumbers; ציבורי רציף מספרים (int totalNumbers) {this.totalNumbers = totalNumbers; } ציבורי ארוך getTotalSum () {totalSum = 0; עבור (int i = 0; i <totalNumbers; i ++) {totalSum + = i; } להחזיר totalSum; }}

לאחר מכן, שיטה פשוטה תעשה שימוש בכיתה לביצוע החישוב:

פרטית סטטית ארוכה calcSSum (int n) {החזר ConsconsNumbersSum חדש (n) .getTotalSum (); }

לבסוף, נקרא לשיטה מספר פעמים שונה ונראה מה קורה:

עבור (int i = 1; i <NUMBERS_OF_ITERATIONS; i ++) {calculatorSum (i); }

בריצה הראשונה, אנו הולכים להריץ אותו 1,000 פעמים (פחות מערך הסף של 10,000 שהוזכר לעיל). אם נחפש את הפלט עבור ה- CalcSum () שיטה, לא נמצא אותה. זה צפוי מכיוון שלא קראנו לזה מספיק פעמים.

אם כעת נשנה את מספר האיטרציות ל- 15,000 ונחפש שוב בפלט, נראה:

664 262% com.baeldung.inlining.InliningExample :: main @ 2 (21 בתים) @ 10 com.baeldung.inlining.InliningExample :: calculatorSum (12 בתים) מוטבע (חם)

אנו יכולים לראות שהפעם השיטה ממלאת את תנאי ההטבעה וה- JVM תיאר אותה.

ראוי לציין שוב שאם השיטה גדולה מדי, ה- JIT לא ישתלב בה, ללא קשר למספר האיטרציות. אנו יכולים לבדוק זאת על ידי הוספת דגל נוסף בעת הפעלת היישום:

-XX: FreqInlineSize = 10

כפי שאנו יכולים לראות בפלט הקודם, גודל השיטה שלנו הוא 12 בתים. ה -XX:FreqInlineSize דגל יגביל את גודל השיטה הזכאי להטבעה ל- 10 בתים. כתוצאה מכך, ההטבעה לא אמורה להתקיים הפעם. ואכן, אנו יכולים לאשר זאת על ידי התבוננות נוספת בפלט:

330 266% com.baeldung.inlining.InliningExample :: main @ 2 (21 bytes) @ 10 com.baeldung.inlining.InliningExample :: calcinSum (12 bytes) שיטה חמה גדולה מדי

למרות ששינינו את ערך הדגל כאן לצורך המחשה, עלינו להדגיש את ההמלצה לא לשנות את ערך ברירת המחדל של ה- -XX: FreqInlineSize דגל אלא אם כן הכרחי בהחלט.

5. מסקנה

במאמר זה ראינו מהי שיטת ההטבעה ב- JVM וכיצד ה- JIT עושה זאת. תיארנו כיצד אנו יכולים לבדוק אם השיטות שלנו מתאימות להטבעה או לא, והצענו כיצד להשתמש במידע זה על ידי ניסיון לצמצם את גודלן של שיטות ארוכות המכונות לעתים קרובות וגדולות מכדי להיות מונחות.

לבסוף המחשנו כיצד אנו יכולים לזהות שיטה חמה בפועל.

כל קטעי הקוד המוזכרים במאמר נמצאים במאגר GitHub שלנו.