out of memory exception–איך להתחיל לבדוק זליגות זיכרון

13 ביולי 2012

תגיות: , ,
3 תגובות

האם קרה לכם אי פעם שהאפליקציה מתרסקת עם out of memory ?

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

מה בכל זאת עושים כשמקבלים כזו שגיאה.

דבר ראשון נפתח את ה – Task Manager ונסתכל מה קורה לפרוסס כשמריצים אותו.

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

בדוגמא שעליה מתבסס הפוסט – מדובר היה בקוד שמשתמש ב – XmlReader כדי לקרוא מידע מקבצי xml (בגודל 200M) ולייצר ממנו אובייקטים, הקוד התחיל לרוץ ובמהירות הגיע לתפוסה של יותר מ – 1.6G והתרסק עם out of memery.

image

הרמתי טלפון לדימה (אחד מהיועצים הכי טובים בארץ של סלע לעולמות ה –debugging and performance), ושאלתי אותו כיצד להתחיל לבדוק מי גורם לזליגת הזיכרון.

ראשית הייתי צריך להתקין את windbg.

לאחר מכן לפתוח אותו (עם הרשאות מנהל – Run As Administrator).

נקבל את החלון הבא:

image

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

image

נבחר את הפרוסס שלנו ונלחץ OK.

נקבל את הדיאלוג הבא:

image

נבחר ב – No.

באותו רגע הפרוסס שלנו יפסיק לרוץ (כמו break point), ונקבל את המסך הבא:

image

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

כעת בתיבת הטקסט נכתוב את הקוד הבא:

.loadby sos clr

כעת נלחץ על אנטר.

(זו הפקודה עבור .NET 4 (בגרסה 2 זה .loadby sos mscorwks). זה טוען WinDbg extension (פלאגין) שמוסיף יכולות ל – WinDbg. במקרה זה, היכולת היא דיבוג managed code. זה טוען את SOS.DLL מאותה תיקיה המכילה את CLR.DLL)

לאחר מכן נכתוב:

!DumpHeap -stat

נלחץ על אנטר ונמתין מספר שניות.

נקבל בחלון רשימה של כל האובייקטים המוגדרים בזיכרון, כמה מופעים מהם, מה הגודל שלהם ומה ה – Method Table. (סיכום סטטיסטי עבור כל type. ללא הפרמטר –stat היינו באמת מקבלים את רשימת כל האובייקטים ה – managed.)

image

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

image

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

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

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

כעת נכתוב את השורה הבאה:

!DumpHeap -mt [method table]

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

!DumpHeap -mt 0040a364

אחרי שנלחץ על אנטר, נתחיל לקבל תוצאות עבור כל אותם תשעה מיליון, כדאי ללחוץ בשלב מסויים על ctrl+brak, כדי לעצור את הריצה.

image

הרשימה מכילה כתובת מדויקת של כל אובייקט (הערך השמאלי).

נכתוב את הקוד הבא:

!gcroot 02534edc

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

כעת אנחנו אמורים לקבל את האובייקט וכל דרך ההצבעה אליו (אם נקבל 0 root זה אומר שזה אובייקט זבל שה – GC אמור לנקות אותו מתי שהוא)

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

הוסף תגובה
facebook linkedin twitter email

כתיבת תגובה

האימייל לא יוצג באתר. שדות החובה מסומנים *

3 תגובות

  1. שחר ג13 ביולי 2012 ב 13:38

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

    הגב
  2. שלומי הסן13 ביולי 2012 ב 19:55

    אחלה פוסט מאוד שימושי

    הגב
  3. שלומי הסן13 ביולי 2012 ב 19:55

    אחלה פוסט מאוד שימושי

    הגב