здрасти

Мисля, че няма да се изненадате твърде много, ако ви кажа, че вашият компютър има ограничено количество памет :) Дори твърд диск — обикновено многократно по-голям от RAM паметта — може да бъде опакован докрай с любимите ви игри, телевизионни предавания, и още. За да предотвратите това, трябва да наблюдавате текущото състояние на паметта и да изтриете ненужните файлове от вашия компютър. Какво общо има програмирането на Java с всичко това? Всичко! В крайна сметка, когато Java машината създава няHowъв обект, тя разпределя памет за този обект.

В една истинска голяма програма се създават десетки и стотици хиляди обекти и всеки от тях има своя собствена част от паметта, разпределена за него. Но колко дълго мислите, че съществуват всички тези обекти? Дали те „живеят“ през цялото време, докато работи нашата програма? Разбира се, че не. Дори и с всички предимства на Java обектите, те не са безсмъртни :) Обектите имат свой собствен жизнен цикъл. Днес ще направим малка почивка от писането на code и ще разгледаме този процес :) Освен това, той е много важен за вашето разбиране How работи една програма и How се управляват ресурсите. И така, кога започва животът на един обект? Като човек - от неговото раждане, тоест създаване.


Cat cat = new Cat(); // Here the lifecycle of our Cat object begins!

Първо, виртуалната машина на 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;

   }

}

Обектът кола Lamborghini Diablo спира да бъде жив на втория ред на main()метода. Имаше само една препратка към него и след това тази препратка беше зададена равна на 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, наречен събирач на отпадъци (GC), влиза в действие.

Събирачът на отпадъци е вътрешен механизъм на Java, отговорен за освобождаване на памет, т.е. премахване на ненужни обекти от паметта. Има основателна причина, поради която избрахме снимка на прахосмукачка робот тук. В края на краищата, събирачът на боклук работи почти по същия начин: във фонов режим той „обикаля“ около вашата програма, събирайки боклука без практически ниHowви усorя от ваша страна. Неговата задача е да премахва обекти, които вече не се използват в програмата.

Това освобождава памет в компютъра за други обекти. Спомняте ли си, че в началото на урока казахме, че в обикновения живот трябва да наблюдавате състоянието на вашия компютър и да изтривате ненужните файлове? Е, в случай на Java обекти, събирачът на отпадъци прави това instead of вас. Събирачът на боклук работи многократно, докато програмата ви работи: не е нужно изрично да го извиквате or да му давате команди, въпреки че това е технически възможно. По-късно ще говорим повече за него и ще анализираме работата му по-подробно.

Когато събирачът на отпадъци достигне обект, точно преди да унищожи обекта, той извиква специален метод — finalize()— на обекта. Този метод може да освободи други ресурси, използвани от обекта. Методът finalize()е част от Objectкласа. Това означава, че в допълнение към методите equals(), hashCode()и toString(), които сте срещали преди, всеки обект има този метод. Различава се от другите методи по това, че е — How да го кажа — много капризен.

По-специално, не винаги се извиква преди унищожаването на обект. Програмирането е прецизно начинание. Програмистът казва на компютъра да направи нещо и компютърът го прави. Предполагам, че вече сте свикнали с това поведение, така че в началото може да ви е трудно да приемете следната идея: „Преди унищожаването на обектите се извиква finalize()методът на Objectкласа. Или може би не се извиква. Всичко зависи от твоят късмет!"

И все пак е вярно. Java машината сама определя дали да извика finalize()метода за всеки отделен случай. Например, нека опитаме да изпълним следния code като експеримент:


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; // This is when the first object becomes available to the garbage collector
       }
   }

   @Override
   protected void finalize() throws Throwable {
       System.out.println("Cat object destroyed!");
   }
}

Създаваме Catобект и след това в следващия ред code задаваме единствената му референция равна на null. И ние го правим мorони пъти. Ние изрично отменихме finalize()метода, така че той да отпечата низ на конзолата мorон пъти (веднъж за всеки път, когато унищожи обект Cat). Но не! За да бъда точен, стартира се само 37 346 пъти на моя компютър! Тоест, само веднъж от 27 пъти Java машината, инсталирана на моята машина, реши да извика finalize()метода.

В други случаи събирането на боклука става без него. Опитайте се да стартирате този code за себе си: най-вероятно ще получите различен резултат. Както можете да видите, finalize()трудно може да се нарече надежден партньор :) Така че, малък съвет за в бъдеще: не разчитайте на finalize()метода за освобождаване на критични ресурси. Може би JVM ще го извика or може би не. Кой знае?

Ако докато вашият обект е жив, той съдържа някои ресурси, които са изключително важни за производителността, например връзка с отворена база данни, по-добре е да създадете специален метод във вашия клас, за да ги освободите и след това да го извикате изрично, когато обектът вече не е необходими. По този начин ще сте сигурни, че производителността на вашата програма няма да пострада. От самото начало казахме, че работата с паметта и премахването на боклука е много важна и това е вярно. Неправилното боequalsе с ресурси и неразбирането How се почистват ненужните обекти може да доведе до изтичане на памет. Това е една от най-известните програмни грешки.

Ако програмистите пишат codeа си неправилно, всеки път може да се разпределя нова памет за новосъздадени обекти, докато старите, ненужни обекти може да не са достъпни за премахване от събирача на отпадъци. Тъй като направихме аналогия с робот-прахосмукачка, представете си Howво би се случило, ако преди да стартирате робота, разпръснете чорапи из къщата, счупите стъклена ваза и оставите конструктори Лего по целия под. Роботът ще се опита да си свърши работата, разбира се, но в един момент ще се забие.

За да позволите на прахосмукачката-робот да функционира правилно, трябва да поддържате пода в добро състояние и да отстранявате всичко, с което роботът не може да се справи. Същият принцип важи и за събирача на отпадъци на Java. Ако в дадена програма са останали много обекти, които не могат да бъдат почистени (като чорап or конструктор Lego за нашата прахосмукачка-робот), в един момент ще ви свърши паметта. И може не само вашата програма да замръзне — всяка друга програма, работеща на компютъра, може да бъде засегната. Те също може да нямат достатъчно памет.

Не е нужно да запомняте това. Просто трябва да разберете принципа зад това How работи.