JavaRush /Java блог /Random UA /Кава-брейк #210. Усі типи збирачів сміття в Java, про які...

Кава-брейк #210. Усі типи збирачів сміття в Java, про які ви повинні знати

Стаття з групи Random UA
Джерело: Hackernoon Завдяки цій публікації ви дізнаєтеся про сильні та слабкі сторони кожного типу збирачів сміття, які використовуються в Java-розробці. Кава-брейк #210.  Всі типи збирачів сміття в Java, про які ви повинні знати - 1Питання про збирачів сміття (Garbage Collector, GC) можна почути майже в кожній співбесіді. Тому я вирішив зібрати всю необхідну інформацію про них, використовуючи свій улюблений принцип коротко і просто. Для початку почнемо з мети CG і чому нам потрібні кілька типів збирачів сміття. У таких мовах, як C, потрібно зберігати інформацію про об'єкти в пам'яті і писати багато шаблонного коду, щоб звільнити цю пам'ять. Зрозуміло, виток пам'яті — часті гості в таких програмах. Java вирішує проблему витоків пам'яті за допомогою збирача сміття. І ви, як розробник, повинні знати, який збирач сміття найкраще використовувати. Багато залежить від того, де і як працює ваша програма. Вона може працювати на слабкому обладнанні або з великою кількістю об'єктів, або ваша програма має бути дуже швидкою. Виходячи з цих умов, ви повинні налаштувати свій збирач сміття для досягнення бажаної продуктивності. Тож почнемо.

Як JVM працює з пам'яттю

Віртуальна машина Java (JVM) ділить пам'ять на дві області: купа, в якій зберігаються дані програми, і не купа (non-heap), в якій зберігається програмний код та інші дані. Звернімо увагу на область купи. Саме тут наша програма творить нові об'єкти. Усі збирачі сміття засновані з урахуванням того, що багато програм використовують недовговічні об'єкти. Тобто ці об'єкти були створені, потім виконали свою функцію і більше не потрібні. Таких об'єктів більшість. Але деякі об'єкти живуть набагато довше, можливо навіть весь час існування програми. Ось тут і виникає ідея поділу об'єктів на молоде та старе покоління. І нам потрібно часто перевіряти молоде покоління. Справа в тому, що процеси прибирання сміття діляться на мінорне чищення, яке зачіпає тільки молодше покоління, і повне чищення, яке може зачіпати обидва покоління. Пам'ятайте, що збирач сміття – це програма. І для її роботи потрібен час та ресурси вашого комп'ютера. Що також впливає на нашу програму. Як впливає? Наприклад, щоб виконати складання сміття, JVM призупиняє нашу програму. Це називається паузою Stop-The-World (STW). У цей час усі потоки додатків призупинені. Але додаток усередині про це зовсім не підозрює. Для програми час тече рівномірно. Чому це так погано? Ось уявіть, ви пишете якусь програму для обміну або програму для автопілота літака. Ваша програма може "заснути" на одну секунду, і суть вашої проблеми може різко змінитися. Тобто пауза є значним параметром для кожного збирача сміття. Наступне фундаментальне властивість збирача сміття — це загальний час, витрачений складання сміття, стосовно загального часу виконання програми. Що це означає і чому так важливо? Замість однієї великої фази "зупини світ" (Stop-The-World) ми можемо вибрати алгоритм з безліччю маленьких пауз. Невеликі паузи краще, але нічого не буває безкоштовно. І тут ми платимо збільшенням загального часу виконання програми. І ми також маємо це враховувати. Наступний параметр – це кількість апаратних ресурсів. Кожному збирачеві потрібна пам'ять для зберігання інформації про об'єкти та процесор для виконання очищення. Останній параметр – швидкість. Оперативність складання сміття означає, наскільки швидко та ефективно збирач сміття (GC) звільняє пам'ять, яка більше не використовується програмою. Всі ці параметри впливають на алгоритм, який може швидко звільняти пам'ять при мінімальному споживанні ресурсів. Погляньмо на доступні нам збирачі сміття. Для інтерв'ю потрібно знати перші п'ять. Два інших набагато складніші.

Serial GC

Serial GC - це збирач сміття у віртуальній машині Java, який використовувався з самого початку існування Java. Він корисний для програм з маленькою купою та працюючих на менш потужних машинах. Цей збирач сміття ділить купу на регіони, куди входять Eden та Survivor. Регіон Eden - це пул, з якого спочатку виділяється пам'ять більшості об'єктів. Survivor - це пул, що містить об'єкти, що пережабо складання сміття в регіоні Eden. У міру заповнення купи об'єкти переміщуються між регіонами Eden та Survivor. JVM постійно відстежує переміщення об'єктів у регіони Survivor та вибирає відповідний поріг кількості таких переміщень, після чого об'єкти переміщуються до регіону старшого покоління (Tenured). Коли в регіоні Tenured не вистачає місця, у справу вступає повне складання сміття, яке працює з об'єктами обох поколінь. Основною перевагою цього збирача сміття є його низькі вимоги до ресурсів, тому для складання тут досить малопотужного процесора. Головним недоліком Serial GC є тривалі паузи при складанні сміття, особливо якщо йдеться про великі обсяги даних.

Parallel CG

Паралельний збирач сміття (Parallel CG) схожий на послідовний конструктор. Він включає паралельну обробку деяких завдань та можливість автоматичного налаштування параметрів продуктивності. Parallel GC - це збирач сміття у віртуальній машині Java, заснований на ідеях Serial GC, але з додаванням паралелізму та інтелекту. Якщо комп'ютер має більше одного ядра процесора, стара версія JVM автоматично вибирає Parallel GC. Купа тут розділена на ті ж регіони, що й у Serial GC - Eden, Survivor 0, Survivor 1 та Old Gen (Tenured). Однак у складання сміття паралельно беруть участь кілька потоків, і збирач може підлаштовуватися під необхідні параметри продуктивності. У кожного потоку колектора є область пам'яті, яку потрібно очистити. Parallel GC також має налаштування, спрямовані на досягнення необхідної ефективності складання сміття. Складальник використовує статистику попередніх складання сміття для налаштування параметрів продуктивності в майбутніх складаннях. Parallel GC забезпечує автоматичне налаштування параметрів продуктивності та менший час паузи для складання, але є один незначний недолік у вигляді деякої фрагментації пам'яті. Він підходить для більшості програм, але для більш складних програм краще вибрати більш розширені реалізації збирачів сміття. Плюси: У багатьох випадках швидше, ніж Serial GC. Має відмінну швидкість роботи. Мінуси: споживає більше ресурсів і паузи можуть бути досить довгими, але ми можемо налаштувати максимальну тривалість паузи Stop-The-World.

Concurrent Mark Sweep

Складальник сміття Concurrent Mark Sweep (CMS) спрямований на зменшення максимальної тривалості пауз за рахунок виконання деяких завдань зі збору сміття одночасно з потоками програми. Цей збирач сміття підходить для керування великими обсягами даних у пам'яті. Concurrent Mark Sweep (CMS) – це альтернатива Parallel GC у віртуальній машині Java (JVM). Він призначений для додатків, де потрібний доступ до кількох ядр процесора і які чутливі до пауз Stop-The-World. CMS виконує етапи складання сміття паралельно з основною програмою, що дозволяє працювати без зупинки. Він використовує ту ж саму організацію пам'яті, що й збирачі Serial і Parallel, але не чекає заповнення області Tenured перед запуском чищення старого покоління. Натомість він працює у фоновому режимі і намагається зберегти компактність регіону Tenured. Concurrent Mark Sweep починається з початкової фази маркування, яка ненадовго зупиняє основні потоки програми та позначає всі об'єкти, доступні з root. Потім основні потоки програми відновлюють роботу, і CMS починає пошук усіх активних об'єктів, доступних за посиланнями відзначених root-об'єктів. Після маркування всіх живих об'єктів збирач кілька паралельних потоків очищає пам'ять від мертвих об'єктів. Однією з переваг CMS є його спрямованість на мінімізацію часу простою, що має вирішальне значення для багатьох програм. Однак він вимагає жертви у вигляді ресурсів процесора та загальної пропускної спроможністю. Крім того, CMS не стискає об'єкти у старому поколінні, що призводить до фрагментації. Довгі паузи через можливі збої паралельного режиму можуть стати неприємним сюрпризом (хоча вони трапляються нечасто). За наявності достатньої кількості пам'яті CMS вдається уникнути таких пауз. Плюси: Швидкий. Має невеликі паузи Stop-The-World. Мінуси: споживає більше пам'яті, при нестачі пам'яті деякі паузи можуть бути довгими. Не дуже хороший, якщо програма створює багато об'єктів.

Garbage-First

Garbage-First (G1) вважається альтернативою CMS, особливо для серверних програм, що працюють на багатопроцесорних серверах і керують великими наборами даних. Складальник сміття G1 перетворює пам'ять у кілька регіонів однакового розміру, крім великих регіонів (які створюються шляхом злиття традиційних регіонів розміщувати потужних об'єктів). Регіони не обов'язково мають бути організовані в ряд і можуть змінювати приналежність до свого покоління. Невеликі чистки виконуються періодично для молодшого покоління та переміщення об'єктів у регіони Survivor або апгрейду їх до старшого покоління з переведенням до Tenured. Очищення виконується лише в тих регіонах, де потрібно уникнути перевищення бажаного часу. Складальник сам прогнозує та обирає для очищення регіони з найбільшою кількістю сміття. Повне очищення використовують цикл маркування для створення списку живих об'єктів, який працює паралельно з основною програмою. Після циклу маркування G1 перемикається на запуск змішаних чисток, які додають регіони старшого покоління до набору регіонів молодшого покоління, що підлягають очищенню. Складальник сміття G1 вважається більш точним, ніж збирач CMS, у прогнозуванні розмірів пауз і краще розподіляє збір сміття в часі, щоб запобігти тривалим простоям додатків, особливо при великих розмірах купи. Він також не фрагментує пам'ять як збирач CMS. Однак збираче G1 потрібно більше ресурсів процесора для роботи паралельно з основною програмою, що знижує пропускну здатність програми. Плюси: працює краще за CMS. Має коротші паузи. Мінуси: споживає більше ресурсів процесора. Також він споживає більше пам'яті, якщо у нас багато досить великих об'єктів (понад 500 КБ), тому що він поміщає такі об'єкти в один регіон (1-32 МБ).

Epsilon GC

Epsilon GC розроблений для ситуацій, коли складання сміття не потрібне. Він не виконує складання сміття, а використовує TLAB (thread-local allocation buffers, локальні буфери виділення потоку) для виділення нових об'єктів - невеликих буферів пам'яті, які запитують окремі потоки з купи. Величезні об'єкти, що не поміщаються в буфер, вимагають блоки пам'яті спеціально для себе. Коли Epsilon GC вичерпує ресурси, генерується помилка OutOfMemoryError і процес завершується. До переваг Epsilon GC належать менші вимоги до ресурсів і швидше виділення пам'яті для програм, які створюють всі необхідні їм об'єкти під час запуску або запускають недовговічні програми, які не використовують усю виділену пам'ять. Epsilon GC також може допомогти проаналізувати вимоги до ресурсів, які інші збирачі сміття додають до вашої програми. Позитивні якості: Дуже швидкий. Мінуси: не очищає об'єкти :) Наступні два колектори є найпередовішими у своєму роді, але також найскладнішими. Тож розглянемо їх коротко.

ZGC

ZGC може підтримувати паузи на рівні менше мілісекунди навіть під час роботи з величезними обсягами даних. ZGC - це збирач сміття, розроблений Oracle для Java, який призначений для забезпечення високої пропускної здатності та низької затримки при обробці великих куп (до 16 ТБ). ZGC заснований на принципах віртуальної пам'яті та використовує різні кольори маркування для відстеження стану об'єктів під час складання сміття. Плюси: паузи менш мілісекунди, навіть у великих купах, що дуже корисно для додатків, які потребують короткого часу обробки запитів. Він працює з дуже великими купами з гарною пропускною здатністю. ZGC може стискати динамічну пам'ять під час складання сміття. Мінуси: Високе завантаження процесорів та відчутні вимоги до продуктивності, що може сповільнити час запуску програм.

Shenandoah GC

Shenandoah GC - ще один збирач сміття з короткими паузами незалежно від розміру купи. Цей збирач сміття розроблений компанією Red Hat. Він призначений для мінімізації часу, що витрачається додатком на збирання сміття. Як і ZGC, це паралельний збирач, що означає, що він працює під час роботи програми, зводячи до мінімуму паузи. Shenandoah GC використовує "покажчики пересилання" для переміщення об'єктів під час складання сміття. Також він має метод під назвою “усунення бар'єру навантаження” підвищення продуктивності. Плюси: Shenandoah GC може досягти короткого часу паузи, часто менше 10 мс, навіть для масивних куп. Хороша пропускна спроможність. Мінуси: високе завантаження процесора та складність у роботі при великих навантаженнях.

Висновок

Складальники сміття - одне з найскладніших завдань у програмуванні. У цьому напрямі постійно проводять нові розробки. І хоча програмісти дуже рідко вдаються до налаштування GC, вам все ж таки необхідно хоча б поверхово знати, як працює ваш інструмент складання сміття.
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ