JavaRush /בלוג Java /Random-HE /מחזור חיים של אובייקט

מחזור חיים של אובייקט

פורסם בקבוצה
שלום! אני חושב שלא תופתעו יותר מדי אם נגיד לכם שגודל הזיכרון במחשב שלכם מוגבל :) אפילו כונן קשיח, שגדול פי כמה מ-RAM, ניתן למלא עד אפס מקום במשחקים האהובים עליכם, סדרות טלוויזיה, וכולי. כדי למנוע את זה, עליך לעקוב אחר מצב הזיכרון הנוכחי ולמחוק קבצים מיותרים מהמחשב שלך. מה הקשר בין תכנות ג'אווה לכל זה? ישיר! אחרי הכל, כאשר כל אובייקט נוצר על ידי מכונת Java, זיכרון מוקצה עבורו. בתוכנית גדולה אמיתית, נוצרים עשרות ומאות אלפי אובייקטים, שלכל אחד מהם מוקצה פיסת זיכרון משלו. מחזור חיים של אובייקט - 1אבל כמה זמן אתה חושב שכל החפצים האלה קיימים? האם הם "חיים" כל הזמן שהתוכנית שלנו פועלת? ברור שלא. עם כל היתרונות של אובייקטי Java, הם לא בני אלמוות :) לאובייקטים יש מחזור חיים משלהם. היום ניקח הפסקה קטנה מכתיבת קוד ונסתכל על התהליך הזה :) יתרה מכך, חשוב מאוד להבנת פעולת התוכנית וניהול משאבים. אז איפה מתחילים חייו של חפץ? כמו אדם - מלידתו, כלומר הבריאה.
Cat cat = new Cat();//вот сейчас и начался vital цикл нашего an object Cat!
ראשית, ה-Java Virtual Machine מקצה את כמות הזיכרון הדרושה ליצירת האובייקט. ואז היא יוצרת קישור אליו, במקרה שלנו - catכדי שתוכל לעקוב אחריו. לאחר מכן, כל המשתנים מאותחלים, נקרא הבנאי, והנה, האובייקט הטרי שלנו כבר חי את החיים שלו :) תוחלת החיים של אובייקטים שונה, אין כאן מספרים מדויקים. בכל מקרה, במשך זמן מה הוא חי בתוך התוכנית ומבצע את תפקידיה. ליתר דיוק, חפץ "חי" כל עוד יש התייחסויות אליו. ברגע שלא נותרו קישורים, האובייקט "מת". לדוגמה:
public class Car {

   String model;

   public Car(String model) {
       this.model = model;
   }

   public static void main(String[] args) {
       Car lamborghini  = new Car("Lamborghini Diablo");
       lamborghini = null;

   }

}
בשיטה, main()חפץ המכונית למבורגיני דיאבלו מפסיק להיות חי כבר בקו השני. היה רק ​​קישור אחד אליו, ועכשיו הקישור הזה הוקצה null. מכיוון שלא נותרו אזכורים ללמבורגיני דיאבלו, הוא הופך ל"זבל". אין צורך לאפס את הקישור:
public class Car {

   String model;

   public Car(String model) {
       this.model = model;
   }

   public static void main(String[] args) {
       Car lamborghini  = new Car("Lamborghini Diablo");

       Car lamborghiniGallardo = new Car("Lamborghini Gallardo");
       lamborghini = lamborghiniGallardo;
   }

}
כאן יצרנו אובייקט שני, שלאחריו לקחנו את הפניה lamborghiniוהקצאנו אותו לאובייקט החדש הזה. כעת Lamborghini Gallardoישנן שתי הפניות המצביעות על האובייקט, אך Lamborghini Diabloאף אחת לא לאובייקט. לכן החפץ Diabloהופך לזבל. וברגע זה נכנס לפעולה מנגנון ה-Java המובנה שנקרא אוסף האשפה, או במילים אחרות - Garbage Collector, GC.
מחזור חיים של אובייקט - 2
אספן האשפה הוא מנגנון ג'אווה פנימי שאחראי על שחרור זיכרון, כלומר הוצאת חפצים מיותרים ממנו. לא בכדי בחרנו תמונה עם שואב אבק רובוטי כדי לתאר אותה. אחרי הכל, אספן האשפה עובד כמעט באותה צורה: ברקע הוא "נודד" בתוכנית שלך, אוסף אשפה, ובו בזמן אתה כמעט לא מתקשר איתו. תפקידו להסיר אובייקטים שכבר אינם בשימוש בתוכנה. כך, הוא מפנה זיכרון במחשב עבור חפצים אחרים. זוכרים שבתחילת ההרצאה אמרנו שבחיים הרגילים צריך לפקח על מצב המחשב ולמחוק קבצים ישנים? אז, במקרה של חפצי Java, אספן האשפה עושה זאת עבורך. Garbage Collector מופעל פעמים רבות במהלך פעולת התוכנית שלך: אין צורך לקרוא לו ספציפית ולתת לו פקודות, למרות שזה אפשרי מבחינה טכנית. בהמשך נדבר עליו יותר וננתח את תהליך עבודתו ביתר פירוט. ברגע שבו אוסף האשפה מגיע לחפץ, רגע לפני השמדתו, נקראת שיטה מיוחדת על החפץ - finalize(). ניתן להשתמש בו כדי לפנות כמה משאבים נוספים שהאובייקט השתמש בהם. השיטה finalize()שייכת למחלקה Object. כלומר, יחד עם equals(), hashCode()ו toString(), שכבר פגשת קודם, לכל אובייקט יש את זה. ההבדל שלו משיטות אחרות הוא שזה... איך לומר את זה... מאוד קפריזית. כלומר, זה לא תמיד נקרא לפני השמדת חפץ. תכנות זה דבר מדויק. המתכנת אומר למחשב לעשות משהו, והמחשב עושה את זה. אתה כנראה כבר רגיל להתנהגות הזו, ואולי יהיה לך קשה בהתחלה לקבל את הרעיון: "לפני שאובייקטים מושמדים, שיטת finalize()המחלקה נקראת Object. או שזה לא נקרא. אם יתמזל מזלנו!" עם זאת, זה נכון. מכונת ה-Java בעצמה קובעת אם לקרוא לשיטה finalize()בכל מקרה ספציפי או לא. לדוגמה, בוא ננסה להפעיל את הקוד הבא לצורך הניסוי:
public class Cat {

   private String name;

   public Cat(String name) {
       this.name = name;
   }

   public Cat() {
   }

   public static void main(String[] args) throws Throwable {

       for (int i = 0 ; i < 1000000; i++) {

           Cat cat = new Cat();
           cat = null;//вот здесь первый an object становится доступен сборщику мусора
       }
   }

   @Override
   protected void finalize() throws Throwable {
       System.out.println("Объект Cat уничтожен!");
   }
}
אנו יוצרים אובייקט Catובשורת הקוד הבאה מאפסים את ההתייחסות היחידה אליו. וכך - מיליון פעמים. דרכנו במפורש את השיטה finalize(), והיא צריכה להדפיס את המחרוזת לקונסולה מיליון פעמים, בכל פעם לפני השמדת האובייקט Cat. אבל לא! ליתר דיוק, זה רץ רק 37,346 פעמים במחשב שלי! כלומר, רק במקרה 1 מתוך 27 החליטה מכונת הג'אווה שהתקנתי לקרוא לשיטה finalize()- במקרים אחרים איסוף האשפה התנהל בלי זה. נסה להריץ את הקוד הזה בעצמך: סביר להניח שהתוצאה תהיה שונה. כפי שאתה יכול לראות, finalize()קשה לקרוא לזה שותף אמין :) לכן, עצה קטנה לעתיד: לא צריך להסתמך על השיטה finalize()במקרה של שחרור משאבים קריטיים. אולי ה-JVM יקרא לזה, אולי לא. מי יודע? אם במהלך חייו האובייקט שלך תפס כמה משאבים שהיו סופר חשובים לביצועים, למשל, הוא שמר על חיבור פתוח למסד הנתונים, עדיף ליצור שיטה מיוחדת בכיתה שלך כדי לשחרר אותם ולקרוא לזה במפורש כשהאובייקט הוא כבר לא נחוץ. כך תדעו בוודאות שביצועי התוכנית שלכם לא ייפגעו. כבר בהתחלה אמרנו שניהול זיכרון ופינוי אשפה חשובים מאוד, וזה נכון. טיפול לא הולם במשאבים וחוסר הבנה של תהליך הרכבת חפצים מיותרים עלולים להוביל לדליפות זיכרון. זוהי אחת משגיאות התכנות המפורסמות ביותר. קוד כתוב שגוי על ידי המתכנת יכול לגרום להקצאת זיכרון חדש בכל פעם לאובייקטים חדשים שנוצרו, בעוד שאובייקטים ישנים ומיותרים אינם זמינים להסרה על ידי אספן האשפה. מכיוון שעשינו אנלוגיה עם שואב אבק רובוטי, תארו לעצמכם מה יקרה אם לפני שתפעילו את הרובוט תפזרו גרביים בבית, תשברו אגרטל זכוכית והשארתם סט לגו מפורק על הרצפה. הרובוט, כמובן, ינסה לעשות משהו, אבל בשלב מסוים הוא יתקע.
מחזור חיים של אובייקט - 3
כדי שזה יעבוד כמו שצריך, צריך לשמור על הרצפה במצב טוב ולהוציא משם את כל מה שהשואב לא יכול להתמודד איתו. אספן האשפה עובד על אותו עיקרון. אם נשארו בתוכנה הרבה חפצים שהיא לא יכולה לאסוף (כמו גרב או לגו לשואב אבק רובוטי), בשלב מסוים הזיכרון ייגמר. ולא רק התוכנית שכתבת תקפא, אלא גם כל שאר התוכנות שרצות במחשב באותו רגע. גם להם לא יהיה מספיק זיכרון. כך נראים מחזור החיים של האובייקט ואספן האשפה בג'אווה. אין צורך לשנן את זה: רק להבין את עקרון הפעולה. בהרצאה הבאה נדבר על תהליכים אלו ביתר פירוט, אך לעת עתה תוכלו לחזור לפתרון בעיות JavaRush :) בהצלחה!
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION