עבור לתוכן

מעקב זיכרון ב- C

Featured Replies

פורסם

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

פורסם

יש את bounds checker המפורסמת.

ללינוקס יש את electric fence שלדעתי גם בודקת את זה.

וכמובן יש את גוגל: http://www.google.com/search?q=C+memory+leak+detector

פורסם
  • מחבר

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

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

כמובן שלא הייתי יכול למצוא בלי מילות החיפוש שכתבת.

תודה רבה רבה, היית לי לעזר.

יום טוב.

פורסם

בהצלחה.

thread hijacking ensues!

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

יצא לי לעבוד אם אנשים שאחרי שהצבעתי על דליפה ענו ב-"כן, אל תדאג, אני כבר יריץ את זה ב-bounds checker" - זו טעות!

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

ב-C++ אפשר להשתמש ב-RAII, מצביעים חכמים, ואפילו garbage collection אם הקומפיילר מאפשר.

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

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



typedef struct
{
/* ... */
Y internal_y;
/* ... */
} X;

X* init_X(int a, int b)
{
X* the_x = NULL;
Y* the_y = NULL;
int* temp = NULL;
FILE* f = NULL;

if (a <= 0 || a >= b ) goto error;

f = fopen("file","rb");
if ( f == NULL ) goto error;

/* ... */

the_y = init_Y(a,b);
if (the_y == NULL) goto error;
the_x->internal_y = the_y;

/* ... */

temp = malloc(sizeof(*temp) * a);
if (temp == NULL) goto error;

/* ... */

/* normal exit: (the_y is not released! it is now owned by the_x) */
free(temp);
fclose(f);
return the_x;

error:
/* error exit */
if (temp) free(temp);
if (f) fclose(f);
if (the_y) destroy_Y(the_y);
if (the_x) free(the_x);
return NULL;
}

(נשים את ה-goto כרגע בצד לויכוח אחר.)

לקוד יש כמה יתרונות:

* קל בקלות לראות אם יש או אין דליפה.

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

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

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

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

ארכיון

דיון זה הועבר לארכיון ולא ניתן להוסיף בו תגובות חדשות.

דיונים חדשים