כיצד לחמם את ה- JVM

1. סקירה כללית

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

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

2. יסודות אדריכלות של JVM

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

  1. טעינת מחלקת האתחול: ה "Bootstrap Class Loader”טוען קוד Java ושיעורי Java חיוניים כגון java.lang. אובייקט לזיכרון. שיעורים טעונים אלה שוכנים ב JRE \ lib \ rt.jar.
  2. כיתת הרחבה טוענת: ExtClassLoader אחראי לטעינת כל קבצי ה- JAR הממוקמים ב- java.ext.dirs נָתִיב. ביישומים שאינם מבוססי Maven או שאינם מבוססי Gradle, שם מפתח מוסיף JARs באופן ידני, כל אותם שיעורים נטענים בשלב זה.
  3. כיתת יישום טעינה: AppClassLoader טוען את כל הכיתות הנמצאות בנתיב מחלקת היישום.

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

3. מה מחמם את ה- JVM

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

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

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

תהליך זה של כוונון ה- JVM ידוע כחימום.

4. קומפילציה מדורגת

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

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

-XX: CompileThreshold -XX: TieredCompilation

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

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

יישומים הפועלים ב- JBoss וב- JDK גרסה 7 כאשר ארגומנט VM זה מופעל נוטים לקרוס לאחר זמן מה עקב באג מתועד. הבעיה תוקנה בגרסת JDK 8.

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

החלק הבא מדגים כיצד ניתן ליישם זאת.

5. יישום ידני

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

ראשית, עלינו ליצור שיעור דמה בשיטה רגילה:

Dummy בכיתה ציבורית {public void m () {}}

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

מחלקה ציבורית ManualClassLoader {עומס חלל סטטי מוגן () {עבור (int i = 0; i <100000; i ++) {דמה דמה = דמה חדשה (); dummy.m (); }}}

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

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

עלינו להריץ את היישום פעמיים; פעם אחת עם לִטעוֹן() קריאת שיטה בתוך הבלוק הסטטי ופעם אחת ללא קריאת שיטה זו:

מחלקה ציבורית MainApplication {static {long start = System.nanoTime (); ManualClassLoader.load (); סוף ארוך = System.nanoTime (); System.out.println ("זמן חימום:" + (סוף התחלה)); } ראשי ריק סטטי ציבורי (String [] args) {התחלה ארוכה = System.nanoTime (); ManualClassLoader.load (); סוף ארוך = System.nanoTime (); System.out.println ("סה"כ זמן לקח:" + (סוף התחלה)); }}

להלן התוצאות משוכפלות בננו-שניות:

עם התחממותאין התחממותהֶבדֵל(%)
1220056 8903640 730
1083797 13609530 1256
1026025 9283837 905
1024047 7234871 706
868782 9146180 1053

כצפוי, בגישה לחימום מופיעה ביצועים טובים בהרבה מהרגיל.

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

6. כלים

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

כדי להשתמש בו עלינו להוסיף תלות נוספת ל- pom.xml:

 org.openjdk.jmh jmh-core 1.19 org.openjdk.jmh jmh-generator-annprocess 1.19 

אנו יכולים לבדוק את הגרסה האחרונה של JMH במאגר המרכזי.

לחלופין, אנו יכולים להשתמש בתוסף Maven של JMH כדי ליצור פרויקט לדוגמה:

ארכיטיפ mvn: צור \ -DinteractiveMode = false \ -DarchetypeGroupId = org.openjdk.jmh \ -DarchetypeArtifactId = jmh-java-benchmark-archetype \ -DgroupId = com.baeldung \ -DartifactId = test \ -Dversion = 1.0

לאחר מכן, בואו ליצור a רָאשִׁי שיטה:

סטטי ציבורי ריק ריק (String [] args) זורק RunnerException, IOException {Main.main (args); }

כעת עלינו ליצור שיטה ולהערות עליה עם JMH @ בנצ'מרק ביאור:

@Benchmark פנויה ריקה init () {// קטע קוד}

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

7. רף ביצועים

ב -20 השנים האחרונות, מרבית התרומות לג'אווה היו קשורות ל- GC (Garbage Collector) ו- JIT (Just In Time Compiler). כמעט כל מדדי הביצועים שנמצאים ברשת נעשים ב- JVM שכבר פועל זמן מה. למרות זאת,

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

כאן HotTub מייעד את הסביבה בה JVM התחמם.

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

8. מסקנה

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

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

וכמו תמיד, קוד המקור המלא זמין ב- GitHub.


$config[zx-auto] not found$config[zx-overlay] not found