איסוף זבל בג’אווה

0 640

-פרסומת-

מהו איסוף זבל?

-פרסומת-

זבל מתייחס לכל אובייקט שאינו בשימוש עוד בתוכנית. המכונה הוירטואלית של ג’אווה (JVM) תתייחס לאובייקט כזבל כאשר אין רפרנסים (הפניות- references) המצביעים עליו. מכאן שאיסוף זבל הוא מציאת אובייקטים שאין בהם עוד צורך ושיחרור הזיכרון שלהם לטובת מערכת ההפעלה.

כיצד מתבצע איסוף הזבל בג’אווה

בג’אווה (כמו בשפות מונחות עצמים מודרניות אחרות) קיים מנגנון הנקרא “אוסף זבל” (Garbage Collector) האחראי על מציאת אובייקטים שאינם בשימוש ושיחרור הזיכרון שלהם (memory release). מנגנון זה עוקב ויודע אילו אובייקטים נוצרים במהלך ותוכנית ואילו הפניות פונות לכל אחד, כך הוא יכול לזהות אובייקט שאינו מוצבע עוד. לצורך שיחרור זיכרון של אובייקטים, הוא מריץ את המתודה finalize() (מתודה הורסת- deconstructor) על האובייקטים שאינם עוד בשימוש. מנגנון איסוף הזבל פועל ב”נים” (תהליכון- thread) נפרד מהתוכנית המורצת בג’אווה בתוך המכונה הוירטואלית JVM. נים זה  פועל בעדיפות נמוכה מאוד בעוד שהתוכנית מקבלת את רוב כוח העיבוד של המעבד (עדיפות גבוהה high priority). בדרך זו מושגת פגיעה מינימלית בביציעים של התוכנית כי עיקר עבודתו של אוסף הזבל תיהיה כאשר לא קיים עומס על המעבד. מצד שני, ייתכן מצב שבו אובייקטים שאינם בשימוש עוד לא יהרסו וזיכרונם לא ישוחרר וישוב למערכת ההפעלה. הסיבה לכך היא שהנים פועל בעדיפות נמוכה ופעולות שלו הן פחות קריטיות. עם זאת,  ייתכנו מצבים בהם JVM תבחין כי שיחרור זיכרון ניהיה קריטי וכתוצאה מצריכת זיכרון גבוהה (זיכרון זמין נמוך), היא תעלה זמנית את עדיפות הנים של מנגנון איסוף הזבל כך שהוא ישחרר זיכרון וימנע דליפת זיכרון (memory leak) בהיקף שיגרום להתוכנית או המערכת כולה. התהליך הזמני הזה עשוי להאט את פעולת המערכת. דליפת זיכרון היא מצב שבו אובייקטים שאינם בשימוש תופסים זיכרון בלי שישוחררו במהלך התוכנית.

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

runFinalizersOnExit()   ***

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

*** מתודה זו היא מתודה מיושנת (deprecated) אשר השימוש בה לא מומלץ משום שהיא לא מיועדת לפעול בתוכנית מרובת נימים.

הערה: האובייקטים שישארו עד לסיום התוכניות יהרסו לפי סדר של האחרון שנוצר – יהרס ראשון (עקרון המחסנית). כלומר מתודת ה-finalize() תרוץ מהאובייקט ה”צעיר” ביותר עד ל”ותיק” מבין אלה שטרם שוחררו. אציין שאובייקטים מוכלים (composed objects) נוצרים אחרי האובייקט שבו הם מוכלים (האובייקט המכיל).

נקודה לחידוד- אובייקט נוצר כאשר מזומן הבנאי שלו המקצה לו זיכרון ויוצר אותו- מאתחל אותו, מבחינת הקוד, השימוש באופרטור new.

 בעיות ומגבלות של מנגנון איסוף הזבל

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

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

-פרסומת-

דוגמה ממשית:

public void endless()

{
    int [] array = new int[2000];
    calc(array);
    set(array);
    // *
    while(true){}
}
אחרי המתודה set() איננו זקוקים יותר למערך הגדול אך הוא עדיין בשימוש מבחינת אוסף הזבל שכן המשתנה array מצביע עליו.
פתרון לבעיה בקוד זה תיהיה שיטול ההפניה אל המערך ע”י הוספת השורה הבאה במקום שורת הכוכבית:
array=null;
וכעת אוסף הזבל יוכל להבחין כי אין עוד מצביעים על המערך ולפנות אותו בבוא העת.

תגובות

-פרסומת-

הגב

לא נפרסם את האימייל שלך.