За да разберете този блог, първо трябва да имате добро разбиране за това как работи моделът на паметта на Java, можете да се обърнете към блог, написан на „Модел на паметта на Java“ или в противен случай можете да се обърнете към онлайн ресурси.

Събирането на боклук е техника за управление на паметта, приложена за възстановяване на паметта, която не се използва от приложението, за да се избегнат изтичания на памет и недостиг на памет, докато се изпълнява Java програма.

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

Много хора смятат, че събирането на боклука събира и изхвърля мъртви предмети. В действителност събирането на боклука на Java прави точно обратното! Живите обекти се проследяват, а всичко останало се определя като боклук. Това основно недоразумение може да доведе до много проблеми с производителността.

Какво е жив и мъртъв обект?

Един обект се счита за жив, когато към него се препраща приложение. Веднага щом препратката към обект се загуби и кодът на приложението не може да го достигне, той се счита за мъртъв. Вътрешно върху обектното дърво се формира. Колкото и просто да звучи това, повдига въпрос: коя е първата препратка в дървото?

Всяко дърво на обекти има един или повече корени, докато тези корени са достъпни, цялото дърво е достъпно. Така че възниква въпросът кога са достъпни корените? Специални обекти, наречени корени за събиране на боклук, са винаги достъпни, така че обектите, които имат тези като корен.

Тези корени могат да бъдат всякакви

  1. Стек от нишки, имащ локална променлива, която съдържа препратка към обект, който от своя страна може да има препратка към други обекти и така нататък, образувайки дърво
  2. Статичните променливи се препращат от клас, което прави класа по подразбиране GC корен, така че когато класът е събран за боклук, препратката също се събира.
  3. Активните нишки на Java също са корени на GC.

Така че наистина е въпрос на вземане на всяка начална точка (всяка локална променлива, глобални, статични, всичко в други нишки и стекови рамки) — всеки корен — и рекурсивно следване на всички препратки, за да се състави списък на всички „живи” обекти: обекти, които се използват и не са подходящи за изтриване. Всичко останало е боклук, който чака да бъде прибран.

След като разберем какво е корен на GC и как се формира дърво, можем да разгледаме алгоритъма, използван от GC за възстановяване на паметта. GC използва алгоритъм за маркиране и почистване, за да възстанови неизползваната памет.

Доста интуитивно е, че този алгоритъм има процес от две стъпки: -

  1. JVM изпълнява този алгоритъм периодично, за да премине и да маркира обектите като живи, които са достъпни.
  2. Цялата хийп памет, която не е заета от маркирани обекти, се възстановява. Той просто е маркиран като свободен, по същество освободен от неизползвани обекти.

Може да се случи някои от обектите, които не се използват от приложението, да са все още достъпни, просто защото разработчикът е забравил да ги дереферира. Такова логическо изтичане на памет не може да бъде изтрито от никакъв софтуер.

Накрая бих искал да спомена, че въпреки че събирането на боклук има своето предимство, то идва на цената на производителността, тъй като се управлява от JVM периодично.