Коротше кажучи : сміттєзбірники не використовують рекурсії. Вони просто керують трасуванням, відслідковуючи фактично два набори (які можуть поєднуватися). Порядок відстеження та обробки осередків не має значення, що дає значну свободу реалізації для представлення наборів. Отже, існує багато рішень, які насправді дуже дешеві у використанні пам'яті. Це важливо, оскільки GC називається саме тоді, коли в купі не вистачає пам'яті. Речі дещо відрізняються з великими віртуальними пам’ятками, оскільки нові сторінки можна легко виділити, а враження - це не брак місця, а відсутність локальності даних
.
Я припускаю, що ви розглядаєте питання про пошук сміттєзбірників, не рахуючи посилань, на які, схоже, ваше питання не стосується.
Питання фокусується на вартості пам'яті відстеження для відстеження набору: множина U (для необробленого) доступних комірок пам’яті, які все ще містять покажчики, які ще не відстежені. Це лише половина проблеми з пам’яттю
для вивезення сміття. GC також повинен відслідковувати інший набір: набір (для відвідуваних) усіх комірок, які виявилися доступними, щоб повернути всі інші комірки в кінці процесу. Обговорювати одне, а не інше має обмежений сенс, оскільки вони можуть мати подібну вартість, використовувати подібні рішення і навіть поєднуватись.V
Перше, що слід зауважити, - це те, що всі трасируючі GC дотримуються тієї ж абстрактної моделі, що базується на систематичному дослідженні спрямованого графіка комірок у пам'яті, доступному з програми, де комірки пам'яті є вершинами, а покажчики - напрямними краями. Для цього використовуються такі набори:
набір (відвіданих) комірок, які вже виявилися доступними мутатором , тобто програма або алгоритм, для якого виконується GC. Множина V розділена на дві роз'єднані підмножини:
V = U ∪ T ;VVV= U∪ Т
безліч (без відстеження) відвідуваних осередків з покажчиками, які ще не були виконані;U
безліч (простежено) відвідуваних осередків, на яких були простежені всі їх вказівники.Т
ми також відзначимо Н
Тільки і U , або U іVUUТ
Алгоритм починається з деяких кореневих покажчиків, відомих системі запуску часу (як правило, покажчики в пам'яті, виділеній стеком), і розміщує всі комірки, які вони вказують, у нетренований набір (звідси вUV
Потім колектор приймає осередки в по черзі і перевіряє на кожну клітинку c всі її вказівники. Для кожного вказівника, якщо загострена комірка знаходиться у V , тоді нічого не робиться, інакше загострена комірка додається до U , оскільки її покажчики ще перевірені. Коли всі його покажчики були оброблені, комірка c переноситься з непрограмованого набору U у відстежений набірUcVUcUТ
Трасування закінчується, коли порожній. Це має відбутися, оскільки жодна комірка не проходить через U більше одного разу. У цьому моменті V = T , і всі комірки в V, як відомо, є доступними для програми, тому не підлягають відшкодуванню. Доповнення H - V офUUV= ТVН- VV
Детально, деталі можуть залежати від того, як реалізуються набори, а також від того, чи є це і U , або U іVUUТ
Я також пропускаю деталі про те, що таке клітинка, чи є вони в одному розмірі чи багато, як ми знаходимо в них покажчики, як вони можуть бути ущільнені, та ще безліч інших технічних питань, які ви можете знайти в книгах та опитуваннях щодо збору сміття .
Можливо, ви помітили, що це надзвичайно простий алгоритм. Не існує рекурсії, а лише цикл на елементах множини який може зростати в міру його обробкиU , поки з часом він не спорожняється. Немає апріорного припущення про додаткову пам'ять.
Все, що дозволяє ідентифікувати набори, і робити досить дешево, необхідні операції. Зауважте, що порядок оброблення комірок не має значення (немає конкретної потреби у складі висувного стеку), що дає багато свободи для вибору засобів для ефективного представлення наборів.
Там, де відомі реалізації відрізняються, полягає в тому, як насправді представлені ці набори. Насправді було використано багато методик:
бітова карта: деякий простір пам’яті зберігається для карти, яка містить один біт для кожної комірки пам’яті, який можна знайти за допомогою адреси комірки. Біт увімкнено, коли відповідна комірка знаходиться у наборі, визначеному картою. Якщо використовуються лише бітові карти, вам потрібно лише 2 біти на комірку.
також ви можете мати місце для спеціального біта тегів (або 2) у кожній комірці, щоб позначити його.
журнал2pp - кількість покажчиків на комірку, а це ще більше зменшується за допомогою стеків бітів.
ви можете перевірити присудок на вміст клітини та її вказівники.
Ви можете перенести комірку у вільну частину пам'яті, призначену для всіх лише осередків, що належать до представленого набору.
VТТU .
ви можете комбінувати ці методи навіть для одного набору.
Як було сказано, все вищезазначене використовувалося деяким реалізованим сміттєзбірником, як це не здається дивним. Все залежить від різних обмежень реалізації. І вони можуть бути досить дешевими у використанні пам’яті, можливо, допомагають при обробці політики замовлення яку можна вільно обирати для цієї мети, оскільки вони не мають значення для кінцевого результату.
Що може здатися найдивнішим, перенесення комірок на нову область насправді дуже поширене: воно називається колекцією копій. В основному використовується з віртуальною пам'яттю.
Зрозуміло, що рекурсії немає, і стек алгоритму мутатора використовувати не потрібно.
Ще одним важливим моментом є те, що багато сучасних ГК реалізовані для великих віртуальних пам’яток . Тоді отримання місця для реалізації та додаткового списку чи стеку не є проблемою, оскільки нові сторінки можна легко виділити. Однак у великих віртуальних спогадах еннемія - це не брак місця, а відсутність локальності . Тоді структура, що представляє набори, та їх використання повинні бути спрямовані на збереження місцевості структури даних та виконання GC. Проблема - не простір, а час. Неадекватна реалізація, швидше за все, виявить неприйнятне уповільнення, ніж переповнення пам'яті.
Я не давав посилань на безліч конкретних алгоритмів, що виникають внаслідок різних комбінацій цих методик, оскільки це здається досить довгим.