CodeGym /בלוג Java /Random-HE /מחזור חיים של אובייקט
John Squirrels
רָמָה
San Francisco

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

פורסם בקבוצה
היי! אני חושב שלא תופתע מאוד אם אגיד לך שלמחשב שלך יש כמות מוגבלת של זיכרון :)
מחזור חיים של אובייקט - 1
אפילו הכונן הקשיח שלך (שגודלו פי כמה וכמה מ-RAM) יכול להיות מלא במשחקים, תוכניות טלוויזיה ודברים אחרים האהובים עליך. כדי למנוע זאת, עליך לעקוב אחר המצב הנוכחי של זיכרון המחשב ולמחוק קבצים מיותרים. איך כל זה קשור לתכנות ג'אווה? די ישירות! אחרי הכל, יצירת אובייקט כלשהו גורמת למכונת Java להקצות לו זיכרון . תוכנית גדולה בעולם האמיתי יוצרת עשרות או מאות אלפי אובייקטים, ונתח זיכרון מוקצה לכל אחד מהם. אבל מה אתה חושב, כמה מהאובייקטים האלה קיימים? האם הם "חיים" כל הזמן שהתוכנית שלנו פועלת? ברור שלא. אפילו עם כל היתרונות שלהם, אובייקטי Java אינם בני אלמוות :) לאובייקטים יש מחזור חיים משלהם. היום ניקח הפסקה קטנה מכתיבת קוד ונחקור את התהליך הזה :) זה גם מאוד חשוב להבנת איך תוכנית עובדת ולניהול משאבים. אז, היכן מתחילים חייו של חפץ? כמו אדם, מלידה, כלומר כשהוא נוצר.
Cat cat = new Cat();// Our Cat object's lifecycle begins now!
ראשית, המכונה הוירטואלית Java מקצה את הזיכרון הדרוש ליצירת האובייקט. ואז הוא יוצר אליו הפניה (במקרה שלנו, 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 Gallardoהאובייקט, אך Lamborghini Diabloלאובייקט אין אף אחת. זה אומר שהאובייקט Diabloהופך לזבל. זה כאשר אוסף האשפה המובנה (GC) של Java נכנס לפעולה.
מחזור חיים של אובייקט - 2
אספן האשפה הוא מנגנון ג'אווה פנימי שאחראי לפינוי זיכרון, כלומר הסרת חפצים מיותרים מהזיכרון. יש סיבה למה בחרנו לייצג את זה עם שואב אבק רובוטי. אוסף האשפה עובד בערך באותו אופן: הוא "זז" בתוכנית שלך ברקע, אוסף אשפה. אתה כמעט לא צריך לתקשר עם זה. תפקידו הוא למחוק אובייקטים שכבר אינם בשימוש בתוכנה. לפיכך, הוא מפנה זיכרון לאובייקטים אחרים. זוכרים שבתחילת השיעור אמרנו בחיים האמיתיים צריך לפקח על מצב המחשב ולמחוק קבצים ישנים? אם אנחנו מדברים על אובייקטי Java, אספן האשפה עושה זאת עבורך . אוסף האשפה מופעל פעמים רבות בזמן שהתוכנית שלך פועלת: אתה לא צריך לקרוא לו במפורש ולתת לו פקודות (אם כי זה אפשרי מבחינה טכנית). נדבר יותר על אספן האשפה בהמשך וננתח כיצד הוא פועל ביתר פירוט. כאשר אוסף האשפה מגיע לחפץ - רגע לפני שהוא מושמד - finalize()נקראת השיטה המיוחדת של החפץ. ניתן להפעיל שיטה זו כדי לשחרר משאבים נוספים מסוימים המשמשים את האובייקט. השיטה finalize()שייכת למחלקה Object. במילים אחרות, זה דומה ל- equals(), hashCode()ו toString()(שפגשת בעבר). לכל חפץ יש את זה . זה שונה משיטות אחרות בכך ש...איך נגיד את זה...זה מאוד מכוון. בכך אנו מתכוונים שלא תמיד קוראים לזה לפני שאובייקט מושמד . תכנות היא פעילות מאוד מדויקת. המתכנת אומר למחשב לעשות משהו, והמחשב עושה את זה. אני מניח שהתרגלת לסוג זה של התנהגות, אז בהתחלה אולי יהיה לך קשה לקבל את הרעיון הבא: "לפני שאובייקט מושמד, השיטה של ​​מחלקת האובייקט נקראת. או לא. finalize()אם יתמזל מזלנו! " ובכל זאת, זו המציאות. מחשב 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;// The first object becomes available for garbage collection here
       }
   }

   @Override
   protected void finalize() throws Throwable {
       System.out.println("The Cat is destroyed!");
   }
}
אנו יוצרים Catאובייקט, ובשורה הבאה אנו מאפסים את ההתייחסות היחידה אליו. ואנחנו עושים את זה מיליון פעמים. דרכנו במפורש את finalize()השיטה. בכל פעם Catשאובייקט מושמד, עליו להציג מחרוזת - בסך הכל מיליון פעמים. אבל לא! ליתר דיוק, במחשב שלי זה בוצע רק 37346 פעמים! במילים אחרות, מכונת ה-Java שלי החליטה לקרוא לשיטה finalize()רק ב-1 מכל 27 מקרים. במקרים האחרים, איסוף האשפה לא כלל שיחה זו. נסה להריץ את הקוד הזה בעצמך. סביר להניח שתקבל תוצאה שונה. כפי שאתם רואים, קשה לקרוא finalize()לשותף אמין :) אז הנה טיפ קטן לעתיד: אל תסתמכו על השיטה finalize()לשחרור משאבים קריטיים. ה-JVM עשוי לקרוא לזה, ואולי לא. מי יודע? אם האובייקט שלך החזיק כמה משאבים קריטיים לביצועים (לדוגמה, חיבור למסד נתונים פתוח) בזמן שהוא היה בחיים, עדיף ליצור ולקרוא במפורש שיטה מיוחדת כדי לשחרר אותם כאשר האובייקט אינו נחוץ עוד. כך תדע בוודאות שביצועי התוכנית שלך לא ייפגעו. התחלנו בכך שעבודה עם זיכרון ואיסוף אשפה הם נושאים חשובים מאוד, ואכן כך הם. טיפול לא נכון במשאבים ואי הבנה כיצד מנקים חפצים מיותרים יכולים להוביל לאחד הבאגים הכי לא נעימים: דליפות זיכרון . זוהי אחת משגיאות התכנות הידועות ביותר. יש לו אפילו מאמר משלו בוויקיפדיה . קוד כתוב בצורה גרועה יכול ליצור מצב שבו זיכרון מוקצה בכל פעם עבור אובייקטים חדשים שנוצרו, אך אובייקטים ישנים מיותרים אינם זמינים לאיסוף אשפה. מכיוון שכבר עשינו אנלוגיה של שואב אבק רובוט, תארו לעצמכם מה יקרה אם לפני הפעלת הרובוט תפזרו גרביים בכל הבית, תנפצו אגרטל זכוכית והשארתם חלקי לגו על כל הרצפה. מטבע הדברים, הרובוט ינסה לעשות משהו, אבל יום אחד הוא יתפוס.
מחזור חיים של אובייקט - 3
כדי שהשואב יפעל כמו שצריך, צריך לשמור על הרצפה במצב הגון ולאסוף את כל מה שהיא לא יכולה להתמודד איתו. אספן האשפה פועל לפי אותו עיקרון. אם לתוכנית יש הרבה חפצים שהיא לא יכולה לנקות (כמו גרב או לגו לשואב האבק הרובוטי שלנו), יום אחד ייגמר לנו הזיכרון. לא רק שהתוכנית שלך תתקע, גם כל התוכניות האחרות שבמקרה פועלות במחשב. הרי גם להם לא יהיה מספיק זיכרון (אם נחזור לאנלוגיה שלנו, הזכוכית השבורה על הרצפה עוצרת לא רק את השואב, אלא גם את האנשים שגרים בבית). בקיצור, כך נראים מחזור חיי אובייקט ואיסוף אשפה בג'אווה. אתה לא צריך לשנן את זה: מספיק פשוט להבין איך זה עובד. בשיעור הבא נחזור לתהליכים אלו ביתר פירוט. אבל לעת עתה, אתה יכול לחזור לפתור משימות CodeGym :) בהצלחה!
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION