דליפת זיכרון

אובדן זיכרון בתוכנה עקב ניהול לקוי

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

שגיאות תכנות המוליכות לדליפת זיכרון הן נפוצות למדי בשפות תכנות אשר אין להם "איסוף זבל" מובנה אוטומטי ואשר מסתמכות בצורה נרחבת על פעולות עם מצביעים. עם שפות אלו נמנות C ו++C.

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

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

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

דוגמה פשוטה בשפת C

עריכה

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

#include <stdio.h>
#include <stdlib.h>

char* generate_password(int length) {
	char* password = malloc(length+1);
	if (password == 0)
		exit(1); // Memory allocation failed
	for (int i=0; i<length; i++)
		password[i] = 'a' + rand()%('z'-'a');
	password[length] = '\0';
	return password;
}

int main() {
	while (1) {
		int n;
		printf("Enter the length of the password:\n");
		scanf("%d", &n);
		if (n > 0)
			printf("The password is: %s\n", generate_password(n));  // memory leak!
	}
	return 0;
}

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

כלים לאיתור דליפת זיכרון

עריכה

קיימים כלים שונים כגון Purify,‏ Valgrind ו-Insure++ אשר מאפשרים זיהוי דליפות זיכרון בתוכניות C ו++C. יש לציין שניתן לממש יכולת "איסוף זבל" סבירה לתוכניות אלו, אך היא אינה מוחלטת. שיטת העבודה של הזיהוי מתבססת על הרעיון, שכל הקצאה של זיכרון, מתבצעת דרך מודול של הכלי ולא באופן ישיר. כל הפרטים הטכניים על ההקצאה נרשמים. עם סיום ריצת התוכנית, הכלי בודק לאלו הקצאות לא בוצע שחרור, והמפתח יכול לקבל דו"ח מלא עם הפניה לקוד המקור, ובעזרתו לפתור את הבעיה.

ראו גם

עריכה

קישורים חיצוניים

עריכה