תקלת StackOverflow היא תקלה שנגרמת כתוצאה מריבוי קריאות לפונקציות בתוכנית שלנו, מה שיגרום לתוכנית שלנו לקרוס בזמן ריצה.
אך כיצד נוכל להימנע מתקלה זו?
לעיתים, כאשר אנו משתמשים ברקורסיה למשל, אנו עלולים להיתקל במצב שבו הקריאה לפונקציה חוזרת על עצמה בלולאה עד אשר התוכנית קורסת.
מדובר בתקלה בזמן ריצה שיש להימנע ממנה משום שלא נצפתה מראש ע"י ה-compiler, ומציפה לנו את ה-Stack.
קחו לדוגמא את קטע הקוד הבא:
int myNum = 1; add1(myNum); static void add1(int num) { num++; add1(num); }
*שימו לב כי בהחלט לא מומלץ להריץ Code Snippet זה, המחשב שלכם עלול להיתקע.
יצרנו את המשתנה myNum אשר מכיל את הערך 1, ועליו הפעלנו את הפונקציה add1.
פונקציה זו מעלה ב-1 את הערך של הפרמטר אשר מקבלת הפונקציה, וקוראת לעצמה שוב באופן רקורסיבי.
משום שאין לנו שום תנאי יציאה מלולאה זו –
הלולאה חוזרת על עצמה שוב ושוב עד אשר התוכנית קורסת:
כלומר שיכולנו להוסיף תנאי שיעצור אותו בהתאם לצרכים שלנו למשל.
נניח והיינו צריכים שהפעולה תחזור על עצמה עד אשר המשתנה יגיע ל-10,
יכולנו להשתמש ב-ref paramter למשל שיעדכן את המשתנה בכל שינוי ויעצור כשיגיע ל-10:
int myNum = 1; add1(ref myNum); Console.WriteLine(myNum); static void add1(ref int myNum) { if (myNum == 10) { return; } myNum++; add1(ref myNum); }
מחלקת StackOverflowException
החריגה שנזרקת כאשר אנו נתקלים במצב זה נקראת StackOverflowException.
חריגה זו אשר לא ניתן לרשת ממנה יורשת מ-SystemException.
אולם הבעיה היא שלא נוכל "לתפוס" את החריגה באמצעות תחביר try–catch.
החריגה StackOverflowException תמיד תיזרק לפני שתיתפס על ידי ה-try–catch שלנו.
אולם מה שכן נוכל לעשות, זה ליצור חריגה משלנו.
אך עדיין, נצטרך לתת "גג" מוגדר למספר הפעמים שהלולאה יכולה לחזור על עצמה.
כלומר שנגדיר מקסימום למספר הפעמים שהלולאה תחזור על עצמה על מנת שלא תיזרק חריגת StackOverflowException.
ראשית ניצור את החריגה שלנו כך שההודעה שתוצג תכלול את המספר הסופי שהגענו אליו כאשר הגענו לתקרה שהגדרנו:
public class MyException : ApplicationException { public override string Message { get; } public MyException(int num) { Message = $"operation stopped at num = {num}"; } }
ואת שאר התוכנית נכתוב כך שבכל פעם יתבצע חיבור של 5 למספר הנוכחי:
public class Program { static int num = 0; static int topOfStack; const int stackSize = 1000000; const int spaceRequired = 18 * 1024; unsafe static void Main(string[] args) { int var; topOfStack = (int)&var; add5(ref num); } unsafe static void add5(ref int num) { int remaining; remaining = stackSize - (topOfStack - (int)&remaining); if (remaining > spaceRequired) { Console.WriteLine(new MyException(num).Message); return; } num += 5; add5(ref num); } }
וכעת, כשנריץ את התוכנית נוכל לקבל את הפלט הבא:
לסיכום ניתן לומר שעלינו לכתוב את הקוד שלנו בצורה כזו שלא תשאיר פתח למקרה שתיזרק תקלת StackOverflowException .
לקריאה מורחבת על חריגת StackOverflowException באתר של מייקרוסופט יש ללחוץ כאן
לקריאה על Debuging של תקלת StackOverflow בדוטנט באתר של מייקרוסופט יש ללחוץ כאן