ניתוח זיכרון יישום מכליל Java

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

במאמר זה, אעבור על כמה טכניקות היכולות לשמש לזיהוי מקור הצריכה בזיכרון ביישום מכוניה ב-Java.

סוג הזיכרון

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

הזיכרון לא-ערימה כולל זיכרון מקורי שמשמש את ה-JVM עצמו או כל ספרייה שמשמשת בתוך היישום באמצעות JNI (Java Native Interface).

שיטה

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

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

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

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

ניתוח

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

להלן צריכת הזכרון של Docker. היא מראה 254MB. בואו ננסה להצביע על מקור צריכת הזכרון.

סך הכל של הזכרון

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

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

Shell

 

ps --no-header -o rss $(pidof java)

ניתוח הערימה

להלן צריכת זיכרון הערימה כפי שנוצרה על ידי כלי eclipse MAT. הערימה הנשמרת הכוללת מוצגת כ-2.2MB, שזה הרבה יותר נמוך מצריכת הזיכרון הכוללת שמוצגת על ידי Docker ומעידה על שימוש רוב באזור הלא-הערימה.

ניתוח זיכרון מקורי

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

Shell

 

jcmd $(pidof java) VM.native_memory \
    | grep -P "Total.*committed=" \
    | grep -o -P "(?<=committed=)[0-9]+(?=KB)"

ניתוח זיכרון מחוץ לערימה

ניתוח באמצעות Jemalloc ו-Jeprof מגלה ששימוש בזיכרון מקורי מיוחס בעיקר לספריית Tensorflow, עם צריכה כוללת של בערך 112MB.

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

מסקנה

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

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

קישור לקוד היישום הדוגמה

https://github.com/parveensaini/JavaContainerMemoryAnalysis

Source:
https://dzone.com/articles/java-container-application-memory-analysis