• Въпроси за интервю за система тип Java
• Въпроси за интервю за съвпадение на Java (+ отговори)
• Структура на Java клас и въпроси за интервю за инициализация
• Въпроси за интервю за Java 8 (+ отговори)
• Управление на паметта в Java Interview Въпроси (+ отговори) (текуща статия) • Java Generics Interview Въпроси (+ отговори)
• Въпроси за интервю за Java Flow Control (+ отговори)
• Въпроси за интервю за Java Exceptions (+ отговори)
• Въпроси за интервю за Java Annotations (+ отговори)
• Топ пролетни въпроси за интервю
1. Въведение
В тази статия ще разгледаме някои въпроси за управление на паметта, които често се появяват по време на интервюта за разработчици на Java. Управлението на паметта е област, с която не толкова много разработчици са запознати.
Всъщност разработчиците обикновено не трябва да се занимават директно с тази концепция - тъй като JVM се грижи за детайлите. Освен ако нещо не се обърка сериозно, дори опитни разработчици може да не разполагат с точна информация за управлението на паметта под ръка.
От друга страна, тези понятия всъщност са доста разпространени в интервютата - така че нека да влезем направо.
2. Въпроси
Q1. Какво означава изявлението „Паметта се управлява в Java“?
Паметта е ключовият ресурс, който едно приложение изисква да работи ефективно и като всеки ресурс е оскъден. Като такова, разпределянето и освобождаването му от и към приложения или различни части на приложение изискват много грижи и внимание.
Въпреки това, в Java, разработчикът не трябва да разпределя изрично и освобождава паметта - JVM и по-точно Garbage Collector - има задължението да обработва разпределението на паметта, така че разработчикът да не трябва.
Това е в противоречие с това, което се случва в езици като C, където програмист има директен достъп до паметта и буквално препраща към клетките на паметта в своя код, създавайки много място за изтичане на памет.
Q2. Какво представлява събирането на боклука и какви са неговите предимства?
Събирането на боклук е процесът на преглед на паметта на купчината, идентифициране кои обекти се използват и кои не и изтриване на неизползваните обекти.
Използваният обект или препратен обект означава, че някаква част от вашата програма все още поддържа указател към този обект. Неизползван обект или обект без препратки вече не е посочен от никоя част от вашата програма. Така паметта, използвана от обект без препратка, може да бъде възстановена.
Най-голямото предимство на събирането на боклука е, че премахва от нас тежестта на ръчното разпределение / освобождаване на паметта, за да можем да се съсредоточим върху решаването на проблема.
Q3. Има ли недостатъци при събирането на боклука?
Да. Винаги, когато събирачът на боклук работи, това оказва влияние върху производителността на приложението. Това е така, защото всички останали нишки в приложението трябва да бъдат спрени, за да позволи на нишката на събирача на боклук ефективно да си върши работата.
В зависимост от изискванията на приложението, това може да бъде реален проблем, който е неприемлив от клиента. Този проблем обаче може да бъде значително намален или дори елиминиран чрез умела оптимизация и настройка на събирача на боклук и използване на различни GC алгоритми.
Q4. Какво е значението на термина „Stop-The-World”?
Когато нишката на събирача на боклук работи, останалите нишки се спират, което означава, че приложението се спира за миг. Това е аналогично на почистването или опушването на къщи, при което на обитателите се отказва достъп до завършване на процеса.
В зависимост от нуждите на дадено приложение, събирането на боклука „спри света“ може да доведе до неприемливо замразяване. Ето защо е важно да се извърши настройка на събирача на боклук и JVM оптимизация, така че засегнатото замразяване да е поне приемливо.
Q5. Какво са стек и купчина? Какво се съхранява във всяка от тези структури на паметта и как са свързани помежду си?
Стекът е част от паметта, която съдържа информация за извиквания на вложен метод до текущата позиция в програмата. Той също така съдържа всички локални променливи и препратки към обекти от купчината, дефинирани в изпълняваните в момента методи.
Тази структура позволява на времето за изпълнение да се върне от метода, като знае адреса, откъдето е бил извикан, и също така да изчисти всички локални променливи след излизане от метода. Всяка нишка има свой собствен стек.
Купчината е голяма част от паметта, предназначена за разпределение на обекти. Когато създавате обект с новата ключова дума, той се разпределя в купчината. Препратката към този обект обаче живее в стека.
Q6. Какво е генералното събиране на боклук и какво го прави популярен подход за събиране на боклука?
Събирането на боклук от поколения може да бъде свободно дефинирано като стратегия, използвана от събирача на боклук, където купчината е разделена на няколко секции, наречени поколения, всяка от които ще съхранява обекти според тяхната „възраст“ на купчината.
Винаги, когато сметосъбирачът работи, първата стъпка в процеса се нарича маркиране. Тук боклукът събира кои части памет се използват и кои не. Това може да отнеме много време, ако всички обекти в системата трябва да бъдат сканирани.
Тъй като се разпределят все повече и повече обекти, списъкът с обекти расте и расте, което води до все по-дълго време за събиране на боклука. Емпиричният анализ на приложенията обаче показва, че повечето обекти са краткотрайни.
С генерационното събиране на боклука обектите се групират според тяхната „възраст“ по отношение на това колко цикъла на сметосъбиране са оцелели. По този начин по-голямата част от работата се разпространява в различни малки и големи цикли на събиране.
Днес почти всички събирачи на боклук са поколение. Тази стратегия е толкова популярна, защото с течение на времето се оказа оптималното решение.
Q7. Опишете в детайли как работи генералното събиране на боклук
За да разберете правилно как работи събирането на боклуци от поколения, е важно първо да запомните как Java купчината е структурирана, за да улесни събирането на боклук от поколения.
Купчината е разделена на по-малки пространства или поколения. Тези пространства са младо поколение, старо поколение или постоянно поколение и постоянно поколение.
На домакините младите поколение повечето от новосъздадените обекти . Емпирично проучване на повечето приложения показва, че повечето обекти са бързо краткотрайни и следователно скоро стават допустими за събиране. Следователно, новите обекти започват своето пътуване тук и се “издигат” в пространството на старото поколение едва след като са достигнали определена “възраст”.
Терминът „възраст“ в събирането на боклук от поколения се отнася до броя на циклите на събиране, които обектът е оцелял .
Пространството на младото поколение е допълнително разделено на три пространства: пространство на Едем и две пространства за оцеляване като Survivor 1 (s1) и Survivor 2 (s2).
Най- старите домакин поколение обекти, които са живели в памет надхвърля определен "възраст" . Предметите, оцелели при събирането на боклука от младото поколение, се популяризират в това пространство. Като цяло е по-голям от младото поколение. Тъй като е по-голям по размер, събирането на боклука е по-скъпо и се случва по-рядко, отколкото при младото поколение.
В постоянен поколение или по-често се нарича PermGen, съдържа метаданни изисква от JVM за описване на класовете и методите, използвани в заявката. Той също така съдържа низа за съхранение на интернирани низове. Попълва се от JVM по време на изпълнение въз основа на класове, използвани от приложението. Освен това тук могат да се съхраняват класове и методи на библиотека на платформа.
Първо, всички нови обекти се разпределят в пространството на Едем . И двете места за оцелели започват празни. Когато пространството на Рая се запълни, се задейства малко събиране на боклука. Препратените обекти се преместват в първото място за оцеляване. Нереферираните обекти се изтриват.
По време на следващия малък GC, същото се случва и с пространството на Едем. Нереферираните обекти се изтриват, а референтните обекти се преместват в място за оцеляване. В този случай обаче те се преместват във второто оцеляло пространство (S2).
В допълнение, обектите от последния малък GC в първото оцеляло пространство (S1) увеличават възрастта си и се преместват в S2. След като всички оцелели обекти бъдат преместени в S2, пространството S1 и Eden се изчистват. В този момент S2 съдържа обекти с различни възрасти.
При следващата малка GC, същият процес се повтаря. Този път обаче местата за оцелели се превключват. Препратените обекти се преместват в S1 от Eden и S2. Оцелелите обекти са на възраст. Eden и S2 се изчистват.
След всеки малък цикъл за събиране на боклука се проверява възрастта на всеки обект. Тези, които са достигнали определена произволна възраст, например 8 години, се повишават от младото поколение до старото или нестандартното поколение. За всички следващи малки GC цикли обектите ще продължат да се промотират в старото поколение пространство.
Това почти изчерпва процеса на събиране на боклука при младото поколение. В крайна сметка ще бъде извършено основно събиране на боклука на старото поколение, което почиства и уплътнява това пространство. За всеки основен GC има няколко малки GC.
Q8. Кога обектът отговаря на условията за събиране на боклук? Опишете как Gc събира допустим обект?
Обектът отговаря на условията за събиране на боклук или GC, ако не е достъпен от живи нишки или от статични препратки.
Най-ясният случай на обект, който става допустим за събиране на боклук, е ако всички негови препратки са нула. Циклични зависимости без никаква външна референция на живо също са допустими за GC. Така че, ако обект A препраща към обект B и обект B препраща към обект A и те нямат друга референтна информация, тогава обектите A и B ще отговарят на условията за събиране на боклука.
Друг очевиден случай е, когато родителският обект е зададен за нула. Когато кухненски обект вътрешно се позовава на обект в хладилник и обект на мивка, а кухненският обект е зададен за нула, хладилникът и мивката ще станат допустими за събиране на боклука заедно с родителската им кухня.
В9. Как задействате събирането на боклук от Java Code?
Вие, като програмист на Java, не можете да принудите събирането на боклук в Java ; той ще се задейства само ако JVM смята, че се нуждае от събиране на боклук въз основа на размера на купчина Java.
Преди да премахнете обект от паметта, нишката за събиране на боклук извиква метод finalize () на този обект и дава възможност за извършване на всякакъв вид необходимо почистване. Можете също да извикате този метод на обектен код, но няма гаранция, че събирането на боклука ще се случи, когато извикате този метод.
Освен това има методи като System.gc () и Runtime.gc (), който се използва за изпращане на заявка за събиране на боклук към JVM, но не е гарантирано, че събирането на боклука ще се случи.
Q10. Какво се случва, когато няма достатъчно куп място за съхранение на нови предмети?
Ако няма място в паметта за създаване на нов обект в Heap, Java Virtual Machine изхвърля OutOfMemoryError или по-точно java.lang.OutOfMemoryError пространство за купчина.
Q11. Възможно ли е да „възкреси“ обект, който е станал допустим за събиране на боклук?
Когато даден обект стане допустим за събиране на боклук, GC трябва да изпълни метода за финализиране върху него. Методът за финализиране се гарантира, че ще се изпълнява само веднъж, като по този начин GC сигнализира обекта за финализиран и му дава почивка до следващия цикъл.
В метода за финализиране можете технически да „възкресите“ обект, например, като го присвоите на статично поле. Обектът отново ще стане жив и не отговаря на условията за събиране на боклука, така че GC няма да го събира през следващия цикъл.
Обектът обаче ще бъде маркиран като финализиран, така че когато стане отново допустим, методът за финализиране няма да бъде извикан. По същество можете да обърнете този трик „възкресение“ само веднъж за целия живот на обекта. Внимавайте, че този грозен хак трябва да се използва само ако наистина знаете какво правите - обаче разбирането на този трик дава известна представа за това как работи GC.
Q12. Опишете силни, слаби, меки и фантомни референции и тяхната роля в събирането на боклука.
Доколкото паметта се управлява в Java, инженерът може да се наложи да извърши възможно най-много оптимизация, за да сведе до минимум латентността и да увеличи до максимум производителността в критични приложения. Тъй като е невъзможно да се контролира изрично, когато събирането на боклука се задейства в JVM, възможно е да се повлияе как се случва по отношение на обектите, които сме създали.
Java ни предоставя референтни обекти, за да контролираме връзката между обектите, които създаваме, и колектора за боклук.
По подразбиране всеки обект, който създаваме в Java програма, е силно посочен от променлива:
StringBuilder sb = new StringBuilder();
В горния фрагмент новата ключова дума създава нов обект StringBuilder и го съхранява в купчината. След това променливата sb съхранява силна препратка към този обект. Това, което означава за събирача на боклук, е, че конкретният StringBuilder обект изобщо не отговаря на условията за събиране поради силна препратка към него от sb . Историята се променя само когато анулираме sb по този начин:
sb = null;
След извикване на горния ред, обектът тогава ще отговаря на условията за събиране.
Можем да променим тази връзка между обекта и събирача на боклука, като го извием изрично в друг референтен обект, който се намира в пакета java.lang.ref .
Може да се създаде мека препратка към горния обект по следния начин:
StringBuilder sb = new StringBuilder(); SoftReference sbRef = new SoftReference(sb); sb = null;
В горния фрагмент създадохме две препратки към обекта StringBuilder . Първият ред създава силен референтен sb, а вторият ред създава мек референтен sbRef . Третият ред трябва да направи обекта допустим за събиране, но събирачът на боклук ще отложи събирането му поради sbRef .
Историята ще се промени само когато паметта се стесне и JVM е на ръба да изхвърли грешка OutOfMemory . С други думи, обекти само с меки препратки се събират в краен случай за възстановяване на паметта.
А слаб справка може да се създаде по подобен начин, използвайки WeakReference клас. Когато sb е зададен за нула и обектът StringBuilder има само слаба препратка, събирачът на боклук на JVM няма абсолютно никакъв компромис и незабавно ще събере обекта при следващия цикъл.
А справка фантом е подобно на слаб справка и обект само с препратки фантоми ще се събира, без да чака. Въпреки това фантомните препратки се изпращат в опашката веднага щом обектите им бъдат събрани. Можем да анкетираме референтната опашка, за да знаем точно кога е бил събран обектът.
Q13. Да предположим, че имаме кръгова справка (два обекта, които се препращат един към друг). Може ли такава двойка обекти да стане допустима за събиране на боклука и защо?
Да, двойка обекти с кръгова препратка могат да станат допустими за събиране на боклука. Това се дължи на начина, по който събирачът на боклук на Java обработва циркулярни препратки. Той разглежда обектите на живо не когато имат някаква препратка към тях, а когато са достъпни чрез навигация в графата на обекти, започвайки от някакъв корен за събиране на боклук (локална променлива на жива нишка или статично поле). Ако двойка обекти с кръгова препратка не е достъпна от корен, тя се счита за допустима за събиране на боклука.
Q14. Как се представят струните в паметта?
А String например в Java е обект с две области: а овъгляване [] стойност поле и междинно съединение хеш област. Полето стойност е масив от символи, представляващи самия низ, а полето хеш съдържа hashCode на низ, който се инициализира с нула, изчислява се по време на първото извикване на hashCode () и се кешира оттогава. Като любопитен случай на ръба, ако hashCode на низ има нулева стойност, той трябва да бъде преизчислен всеки път, когато hashCode () бъде извикан.
Важното е, че екземпляр String е неизменен: не можете да получите или промените основния масив char [] . Друга характеристика на низовете е, че статичните константи се зареждат и кешират в пул от низове. Ако имате няколко идентични String обекта във вашия изходен код, всички те са представени от един екземпляр по време на изпълнение.
Q15. Какво е Stringbuilder и какви са неговите случаи на употреба? Каква е разликата между добавянето на низ към Stringbuilder и свързването на два струни с оператор +? По какво се различава Stringbuilder от Stringbuffer?
StringBuilder позволява манипулиране на последователности от символи чрез добавяне, изтриване и вмъкване на символи и низове. Това е променлива структура от данни, за разлика от String класа, който е неизменен.
При обединяване на два екземпляра на String се създава нов обект и се копират низове. Това може да доведе до огромен събиране на боклук, ако трябва да създадем или модифицираме низ в цикъл. StringBuilder позволява много по-ефективно обработване на манипулации на низове.
StringBuffer се различава от StringBuilder по това, че е безопасен за нишки. Ако трябва да манипулирате низ в една нишка, вместо това използвайте StringBuilder .
3. Заключение
В тази статия разгледахме някои от най-често срещаните въпроси, които често се появяват в интервюта за инженери на Java. Въпроси относно управлението на паметта се задават най-вече за кандидати за старши разработчици на Java, тъй като интервюиращият очаква, че сте създали нетривиални приложения, които много пъти са измъчвани от проблеми с паметта.
Това не трябва да се третира като изчерпателен списък с въпроси, а по-скоро като стартова площадка за по-нататъшни изследвания. Ние от Baeldung ви пожелаваме успех във всички предстоящи интервюта.
Следващ » Въпроси за интервю за Java Generics (+ отговори) « Предишни въпроси за интервю за Java 8 (+ отговори)