JavaRush /Java блог /Random UA /Життєвий цикл об'єкту

Життєвий цикл об'єкту

Стаття з групи Random UA
Вітання! Думаю, ти не сильно здивуєшся, якщо тобі сказати, що розмір пам'яті на твоєму комп'ютері обмежений:) Навіть жорсткий диск, який у рази більший за оперативну пам'ять, можна забити під зав'язку улюбленими іграми, серіалами та іншим. Щоб цього не сталося, необхідно стежити за поточним станом пам'яті і видаляти з комп'ютера непотрібні файли. Яке відношення до цього має програмування на Java? Пряме! Адже під час створення будь-якого об'єкта Java-машиною під нього виділяється пам'ять. У реальній великій програмі створюються десятки та сотні тисяч об'єктів, під кожен із яких у пам'яті виділяється свій шматочок.Життєвий цикл об'єкту - 1Але як ти думаєш, скільки є всі ці об'єкти? "Чи живуть" вони весь час, поки працює наша програма? Зрозуміло, що ні. За всіх переваг Java-об'єктів, вони не безсмертні :) Об'єкти мають власний життєвий цикл. Сьогодні ми трохи відпочинемо від написання коду і розглянемо цей процес :) Тим більше, що він є дуже важливим для розуміння роботи програми та розпорядження ресурсами. Отже, з чого починається життя об'єкта? Як і в людини — з її народження, тобто створення.
Cat cat = new Cat();//вот сейчас и начался життєвий цикл нашего об'єкта Cat!
Спочатку віртуальна 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()об'єкт машини Lamborghini Diablo перестає бути живим вже на другому рядку. На нього було лише одне посилання, а тепер це посилання було присвоєно null. Оскільки на Lamborghini Diablo не залишилося посилань, він стає "сміттям". Посилання при цьому не обов'язково обнулювати:
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, який відповідає за звільнення пам'яті, тобто видалення з неї непотрібних об'єктів. Ми не дарма вибрали для його зображення картинку з роботом-пилососом. Адже збирач сміття працює приблизно так само: у фоновому режимі він їздить за твоєю програмою, збирає сміття, і при цьому ти з ним практично не взаємодієш. Його робота – видаляти об'єкти, які вже не використовуються у програмі. Таким чином, він звільняє в комп'ютері пам'ять для інших об'єктів. Пам'ятаєш на початку лекції ми говорабо, що у звичайному житті тобі доводиться стежити за станом твого комп'ютера та видаляти старі файли? Так от, у випадку з 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;//вот здесь первый об'єкт становится доступен сборщику мусора
       }
   }

   @Override
   protected void finalize() throws Throwable {
       System.out.println("Объект Cat уничтожен!");
   }
}
Ми створюємо об'єкт Catі вже в наступному рядку коду обнулюємо єдине посилання на нього. І так – мільйон разів. Ми явно перевизначабо метод finalize(), і він повинен мільйон разів вивести рядок у консоль, щоразу перед знищенням об'єкта Cat. Але немає! Якщо бути точним, на моєму комп'ютері він відпрацював лише 37346 разів! Тобто тільки в одному випадку з 27-ми встановлена ​​у мене Java-машина приймала рішення викликати спосіб finalize()- в інших випадках складання сміття проходила без цього. Спробуй запустити цей код у себе: швидше за все, результат відрізнятиметься. Як бачиш, finalize()важко назвати надійним партнером :) Тому невелика порада на майбутнє: не варто покладатися на методfinalize()у випадку зі звільненням якихось критично важливих ресурсів. Може JVM його викличе, а може, ні. Хто знає? Якщо твій об'єкт за життя займав якісь суперважливі для продуктивності ресурси, наприклад, тримав відкритим з'єднання з базою даних, краще створи у своєму класі спеціальний метод для їх звільнення і виклич його явно, коли об'єкт вже буде не потрібен. Так ти точно знатимеш, що продуктивність твоєї програми не постраждає. На самому початку ми сказали, що робота з пам'яттю та видалення сміття є дуже важливими, і це дійсно так. Неналежна робота з ресурсами та нерозуміння процесу складання непотрібних об'єктів можуть призвести до витоку пам'яті. Це одна з найвідоміших помилок у програмуванні. Неправильно написаний програмістом код може призвести до того, що для новостворених об'єктів щоразу виділятиметься нова пам'ять, при цьому старі, непотрібні об'єкти будуть недоступні для видалення збирачем сміття. Якщо ми привели аналогію з роботом пилососом, уяви, що буде, якщо перед запуском робота розкидати по дому шкарпетки, розбити скляну вазу і залишити на підлозі розібраний конструктор Lego. Робот, звичайно, спробує щось зробити, але одного разу він застрягне.
Життєвий цикл об'єкта - 3
Для його правильної роботи потрібно тримати підлогу у нормальному стані та прибирати звідти все, з чим не впорається пилосос. За таким же принципом працює і збирач сміття. Якщо в програмі буде залишатися багато об'єктів, які він не може зібрати (як носок або Lego для робота-пилососа), одного разу пам'ять закінчиться. І зависне як написана тобою програма, а й інші програми, запущені у цей час на комп'ютері. Для них теж не вистачатиме пам'яті. Ось так виглядають у Java життєвий цикл об'єктів та збирач сміття. Це не треба заучувати: досить просто зрозуміти принцип роботи. У наступній лекції ми поговоримо про ці процеси докладніше, а поки що - можеш повернутися до вирішення задач JavaRush :) Успіхів!
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ