לקראת הידור הזמן (AoT)

1. הקדמה

במאמר זה, נבחן את מהדר Java Ahead (Java Ahead), המתואר ב- JEP-295 ונוסף כתכונה ניסיונית ב- Java 9.

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

2. מה לפני הידור הזמן?

אוסף AOT הוא דרך אחת לשיפור הביצועים של תוכניות Java ובמיוחד זמן ההפעלה של ה- JVM. ה- JVM מבצע Java bytecode ומקבץ קוד המבוצע לעתים קרובות לקוד מקורי. זה נקרא קומפילציה Just-in-Time (JIT). ה- JVM מחליט איזה קוד להכין JIT בהתבסס על מידע פרופילי שנאסף במהלך הביצוע.

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

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

3. דוגמא

לדוגמא זו נשתמש בכיתה פשוטה מאוד, נרכיב אותה ונראה כיצד להשתמש בספריה שהתקבלה.

3.1. AOT אוסף

בואו נסתכל במהירות על מחלקת הדוגמאות שלנו:

Class class JaotCompilation {public static void main (String [] argv) {System.out.println (message ()); } הודעת מחרוזת סטטית ציבורית () {return "מהדר JAOT אומר 'שלום'"; }} 

לפני שנוכל להשתמש במהדר AOT, עלינו לקמפל את הכיתה עם מהדר Java:

javac JaotCompilation.java 

לאחר מכן אנו מעבירים את התוצאה JaotCompilation.class למהדר AOT, שנמצא באותה מדריך כמו מהדר Java הרגיל:

jaotc - פלט jaotCompilation.so JaotCompilation.class 

זה מייצר את הספרייה jaotCompilation.so בספרייה הנוכחית.

3.2. הפעלת התוכנית

לאחר מכן נוכל לבצע את התוכנית:

java -XX: AOTLibrary =. / jaotCompilation.so JaotCompilation 

הוויכוח -XX: AOTLibrary מקבל נתיב יחסי או מלא לספריה. לחלופין, אנו יכולים להעתיק את הספרייה אל ה- lib התיקיה בספריית הבית של Java והעבירו רק את שם הספרייה.

3.3. אימות שהספרייה מתקשרת ומשומשת

אנו יכולים לראות שהספרייה אכן הועלה על ידי הוספה -XX: + PrintAOT כטיעון JVM:

java -XX: + PrintAOT -XX: AOTLibrary =. / jaotCompilation.so JaotCompilation 

הפלט ייראה כך:

77 1 נטען ./jaotCompilation.so ספריית aot 

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

java -XX: AOTLibrary =. / jaotCompilation.so -verbose -XX: + PrintAOT JaotCompilation 

הפלט יכיל את השורות:

11 1 טעון ./jaotCompilation.so ספריית aot 116 1 aot [1] jaotc.JaotCompilation. () V 116 2 aot [1] jaotc.JaotCompilation.message () Ljava / lang / String; 116 3 aot [1] jaotc.JaotCompilation.main ([Ljava / lang / String;) V מהדר JAOT אומר 'שלום' 

הספרייה המהוללת של AOT מכילה טביעת אצבע בכיתה, שחייב להתאים לטביעת האצבע של ה- .מעמד קוֹבֶץ.

בואו נשנה את הקוד בכיתה JaotCompilation.java להחזרת הודעה אחרת:

הודעת מחרוזת סטטית ציבורית () {return "מהדר JAOT אומר 'בוקר טוב'"; } 

אם נבצע את התוכנית מבלי ש- AOT ירכיב את המחלקה המתוקנת:

java -XX: AOTLibrary =. / jaotCompilation.so -verbose -XX: + PrintAOT JaotCompilation 

ואז הפלט יכיל רק:

 11 1 טעון ./jaotCompilation.so ספריית aot מהדר JAOT אומר 'בוקר טוב'

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

4. עוד טיעוני AOT ו- JVM

4.1. AOT אוסף של מודולי Java

אפשר גם להרכיב מודול:

jaotc - פלט javaBase.so - מודול java.base 

הספרייה שהתקבלה javaBase.so גודלו כ -320 מגה-בייט ונדרש זמן מה לטעינה. ניתן להקטין את הגודל על ידי בחירת החבילות והשיעורים שייאספו.

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

4.2. אוסף סלקטיבי עם פקודות קומפילציה

כדי למנוע מהספרייה המהוללת של AOT של מודול Java להיות גדולה מדי, אנו יכולים להוסיף פקודות קומפילציה כדי להגביל את היקף מה שמרכיב AOT. פקודות אלה צריכות להיות בקובץ טקסט - בדוגמה שלנו נשתמש בקובץ complileCommands.txt:

הידור רק java.lang. *

לאחר מכן, אנו מוסיפים אותו לפקודת הקומפילציה:

jaotc - פלט javaBaseLang.so - מודול java.base - פקודות קומפילציה compileCommands.txt 

הספריה המתקבלת תכלול רק את שיעורי ה- AOT שנאספו חבילה java.lang.

כדי להשיג שיפור ביצועים אמיתי, עלינו לגלות אילו שיעורים מופעלים במהלך חימום ה- JVM.

ניתן להשיג זאת על ידי הוספת מספר ארגומנטים של JVM:

java -XX: + UnlockDiagnosticVMOptions -XX: + LogTouchedMethods -XX: + PrintTouchedMethodsAtExit JaotCompilation 

במאמר זה לא נצלול עמוק יותר לטכניקה זו.

4.3. AOT אוסף של כיתה יחידה

אנו יכולים לקבץ כיתה אחת עם הטיעון –שם-מחלקה:

jaotc - פלט javaBaseString.so - שם קלאס java.lang.String 

הספרייה המתקבלת תכלול רק את הכיתה חוּט.

4.4. הידור עבור שכבות

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

jaotc - פלט jaotCompilation.so - compile-for-tiered JaotCompilation.class 

בקוד שהורכב מראש בספרייה ישמש עד שהקוד-בתאי יהפוך זכאי לאוסף JIT.

5. מקרי שימוש אפשריים לאוסף AOT

מקרה אחד לשימוש ב- AOT הוא תוכניות הפועלות קצרות, שמסיימות את הביצוע לפני כל אוסף JIT.

מקרה שימוש נוסף הוא סביבות משובצות, בהן JIT אינו אפשרי.

בשלב זה, עלינו לציין כי ניתן לטעון את הספרייה המהודרת של AOT רק ממעמד Java עם קוד byt זהה, ולכן לא ניתן לטעון באמצעות JNI.

6. AOT ו- Amazon Lambda

מקרה שימוש אפשרי לקוד מקומט AOT הוא פונקציות למבדה קצרות מועד בהן זמן הפעלה קצר חשוב. בחלק זה, נבחן כיצד נוכל להפעיל קוד Java מורכב של AOT ב- AWS Lambda.

שימוש באוסף AOT עם AWS למבדה מחייב את הספרייה לבנות על מערכת הפעלה התואמת למערכת ההפעלה המשמשת ב- AWS. בזמן כתיבת שורות אלה אמזון לינוקס 2.

יתר על כן, גרסת Java צריכה להתאים. AWS מספקת את אמזון קורטו Java 11 JVM. כדי שתהיה לנו סביבה להרכיב את הספרייה שלנו, נתקין אמזון לינוקס 2 ו אמזון קורטו בדוקר.

לא נדון בכל הפרטים של השימוש ב- Docker ו- AWS למבדה אלא רק מתאר את הצעדים החשובים ביותר. למידע נוסף על אופן השימוש ב- Docker, עיין בתיעוד הרשמי שלו כאן.

לפרטים נוספים אודות יצירת פונקציית Lambda עם Java, תוכלו לעיין במאמר שלנו AWS Lambda With Java.

6.1. תצורה של סביבת הפיתוח שלנו

ראשית, עלינו למשוך את תמונת ה- Docker עבור אמזון לינוקס 2 ולהתקין אמזון קורטו:

# הורד את ה- docker של אמזון לינוקס משוך את amazonlinux # בתוך מיכל ה- Docker, התקן את Amazon Corretto yum התקן java-11-amazon-corretto # כמה ספריות נוספות הדרושות עבור jaotc yum install binutils.x86_64 

6.2. הידר את הכיתה והספרייה

בתוך מיכל ה- Docker שלנו אנו מבצעים את הפקודות הבאות:

# צור תיקיה aot mkdir aot cd aot mkdir jaotc cd jaotc

שם התיקיה הוא רק דוגמה ויכול להיות, כמובן, כל שם אחר.

חבילה jaotc; מחלקה ציבורית JaotCompilation {הודעת אינטראקציה ציבורית סטטית (קלט int) {קלט חזרה * 2; }}

השלב הבא הוא להרכיב את הכיתה ואת הספרייה:

javac JaotCompilation.java cd .. jaotc -J-XX: + UseSerialGC - פלט jaotCompilation.so jaotc / JaotCompilation.class

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

java -XX: + PrintCommandLineFlags -version

כעת נוכל ליצור קובץ zip המכיל את הספרייה וקובץ המחלקה שלנו:

zip -r jaot.zip jaotCompilation.so jaotc /

6.3. הגדר את תצורת AWS למבדה

השלב האחרון הוא להיכנס למסוף AWS למדה, להעלות את קובץ ה- zip ולהגדיר את Lambda עם הפרמטרים הבאים:

  • זמן ריצה: ג'אווה 11
  • המטפל: jaotc.JaotCompilation :: הודעה

יתר על כן, עלינו ליצור משתנה סביבה בשם JAVA_TOOL_OPTIONS ולהגדיר את ערכו ל:

-XX: + UnlockExperimentalVMOptions -XX: + PrintAOT -XX: AOTLibrary =. / JaotCompilation.so

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

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

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

57 1 נטען ./jaotCompilation.so ספריית aot

7. מסקנה

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

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