Коротко
Фіналізація - справа непроста, з якою вирішуються сміттєзбірники. Його легко використовувати при підрахунку посилань на GC, але це сімейство GC часто неповне, що вимагає компенсації витоків пам'яті шляхом явного запуску руйнування та доопрацювання деяких об'єктів та структур. Відстеження сміттєзбиральників набагато ефективніше, але вони значно ускладнюють ідентифікацію об'єкта, який підлягає доопрацюванню та знищенню, на відміну від просто виявлення невикористаної пам'яті, що вимагає більш складного управління, з витратами у часі та просторі та складністю впровадження.
Вступ
Я припускаю, що ви запитуєте, чому мови, зібрані сміттям, не піддаються автоматичному знищенню / доопрацюванню в процесі вивезення сміття, як зазначено в зауваженні:
Мені вкрай не вистачає, щоб ці мови розглядали пам'ять як єдиний ресурс, яким варто керувати. Що з розетками, ручками файлів, станами програми?
Я не згоден з прийнятою відповіддю, наданою kdbanman . Хоча факти, викладені там, здебільшого вірні, хоча й сильно упереджені щодо підрахунку посилань, я не вірю, що вони належним чином пояснюють ситуацію, на яку скаржиться у питанні.
Я не вірю, що термінологія, розроблена у цій відповіді, є великою проблемою, і це швидше заплутає речі. Дійсно, як представлено, термінологія визначається здебільшого способом активізації процедур, а не тим, що вони роблять. Річ у тім, що у всіх випадках виникає необхідність доопрацювати об’єкт, який більше не потрібен за допомогою певного процесу очищення, та звільнити будь-які ресурси, які він використовував, пам'ять є лише одним із них. В ідеалі все це слід робити автоматично, коли об’єкт більше не використовується, за допомогою сміттєзбірника. На практиці GC може бути відсутнім або мати недоліки, і це компенсується явним запуском програми доопрацювання та рекультивації.
Явна тригеринга програмою є проблемою, оскільки вона може дозволяти важко аналізувати помилки програмування, коли об'єкт, який ще використовується, явно припиняється.
Тому набагато краще покладатися на автоматичне вивезення сміття, щоб повернути ресурси. Але є два питання:
деяка техніка збору сміття дозволить витоку пам'яті, що запобігає повній рекультивації ресурсів. Це добре відомо для підрахунку посилань на GC, але може з'являтися для інших методів GC при використанні деяких організацій даних без уваги (точка тут не обговорюється).
хоча техніка GC може бути хорошою для виявлення ресурсів пам'яті, які вже не використовуються, доопрацювання об'єктів, що містяться в них, може бути непростим, а це ускладнює проблему з поверненням інших ресурсів, які використовуються цими об'єктами, що часто є метою доопрацювання.
Нарешті, важливий момент, про який часто забувають, - це те, що цикли GC можуть спрацьовувати будь-чим, а не лише дефіцитом пам’яті, якщо належні гачки забезпечені і якщо вартість циклу GC вважається вартим. Отже, цілком нормально ініціювати GC, коли будь-який ресурс бракує, сподіваючись звільнити його.
Довідковий підрахунок сміттєзбірників
Підрахунок довідок є слабкою технікою збору сміття , яка не попрацює циклами належним чином. Це дійсно було б слабким для руйнування застарілих структур та відновлення інших ресурсів просто тому, що воно слабке для відновлення пам'яті. Але фіналізатори можуть бути використані найпростіше з посиланням для збору сміття (GC), оскільки перерахунок посилань GC відновлює структуру, коли кількість посилань зменшується до 0, і в цей час його адреса знається разом зі своїм типом, або статично або динамічно. Отже, можливо повернути пам'ять точно після застосування відповідного фіналізатора та виклику рекурсивно процесу на всіх загострених об'єктах (можливо, через процедуру завершення).
Коротше кажучи, доопрацювання легко здійснити за допомогою Count Count GC, але страждає від "незавершеності" цього GC, насправді, завдяки круговим структурам, точно в тій же мірі, в якій відбувається відновлення пам'яті. Іншим словом, при підрахунку посилань пам'ять точно так само керована, як і інші ресурси, такі як сокети, ручки файлів тощо.
Дійсно, нездатність графа GC відновити циклічні структури (загалом) може розглядатися як витік пам'яті . Ви не можете очікувати, що всі GC уникнуть витоків пам'яті. Це залежить від алгоритму GC та інформації про структуру типу, що динамічно доступна (наприклад, у
консервативних GC ).
Відстеження сміттєзбірників
Більш потужна родина GC, без таких витоків, - це сімейство калькування, яке досліджує живі частини пам'яті, починаючи з добре визначених кореневих покажчиків. Усі частини пам'яті, які не відвідуються в цьому процесі відстеження (які фактично можуть бути розкладені різними способами, але я мушу спростити), є невикористаними частинами пам'яті, які можуть бути відтворені таким чином 1 . Ці колектори повернуть усі частини пам'яті, до яких програма більше не може отримати доступ, незалежно від того, що вона робить. Це відновлює кругові структури, і більш досконалі GC засновані на деякій варіації цієї парадигми, іноді дуже складною. Він може поєднуватися з підрахунком посилань в деяких випадках і компенсувати його слабкі сторони.
Проблема полягає в тому, що ваша заява (в кінці питання):
Мови, які пропонують автоматичне вивезення сміття, здаються головними кандидатами на підтримку знищення / доопрацювання об'єктів, як вони знають зі 100% впевненістю, коли об'єкт більше не використовується.
технічно некоректно для відстеження колекторів.
Те, що відомо зі 100% впевненістю, - це те, що частини пам'яті вже не використовуються . (Точніше, слід сказати, що вони більше не доступні , оскільки деякі частини, які вже не можуть бути використані відповідно до логіки програми, як і раніше вважаються у використанні, якщо в програмі все ще є непотрібний покажчик. Дані.) Але необхідна подальша обробка та відповідні структури, щоб знати, які невикористані об'єкти можуть бути збережені в цих не використовуваних частинах пам'яті . Це неможливо визначити з того, що відомо про програму, оскільки програма більше не підключена до цих частин пам'яті.
Таким чином, після передачі сміття вам залишаються фрагменти пам'яті, які містять об'єкти, які вже не використовуються, але апріорі немає способу дізнатися, що це за об'єкти, щоб застосувати правильну доопрацювання. Крім того, якщо колектор відстеження є типом розмітки, можливо, деякі фрагменти можуть містити об'єкти, які вже були доопрацьовані в попередньому проході GC, але з тих пір не використовувалися з міркувань фрагментації. Однак це можна вирішити за допомогою розширеного явного введення тексту.
У той час як простий колектор просто поверне ці фрагменти пам'яті, без подальшої оболонки, для доопрацювання потрібен певний перехід для дослідження цієї невикористаної пам'яті, ідентифікації об'єктів, що містяться там, та застосування процедур доопрацювання. Але така розвідка вимагає визначення типу об’єктів, які там зберігалися, і визначення типу також потрібно для належної доопрацювання, якщо така є.
Таким чином, це передбачає додаткові витрати в GC час (додатковий пропуск) і, можливо, додаткові витрати на пам'ять для надання належної інформації про тип під час цього проходу різними методами. Ці витрати можуть бути значними, оскільки часто хочеться доопрацювати лише декілька об'єктів, тоді як накладні витрати та час можуть стосуватися всіх об'єктів.
Ще один момент полягає в тому, що накладні витрати на час і простір можуть стосуватися виконання програмного коду, а не лише виконання програми GC.
Я не можу дати більш точної відповіді, вказуючи на конкретні питання, тому що я не знаю специфіки багатьох мов, які ви перераховуєте. Що стосується С, типізація є дуже важким питанням, яке призводить до розвитку консервативних колекторів. Я гадаю, що це впливає і на C ++, але я не знаю C ++. Це, мабуть, підтверджує Ганс Боем, який проводив більшу частину досліджень консервативної ГК. Консервативний GC не може систематично повернути всю невикористану пам'ять саме тому, що може не вистачити точної інформації про тип даних. З тієї ж причини не вдалося б систематично застосовувати завершальні процедури.
Отже, можна робити те, що ви запитуєте, як ви знаєте з деяких мов. Але це не приходить безкоштовно. Залежно від мови та її реалізації, це може спричинити за собою витрати навіть тоді, коли ви не використовуєте функцію. Для вирішення цих питань можуть розглядатися різні методи та компроміси, але це виходить за рамки відповіді розумного розміру.
1 - це абстрактне представлення колекції трасування (охоплює як копію, так і зачистку GC), все змінюється залежно від типу колектора трасування, і вивчення невикористаної частини пам’яті відрізняється, залежно від того, копія чи позначка та застосовується зачистка.
finalize
/destroy
це брехня? Немає гарантії, що вона коли-небудь буде виконана. І навіть якщо ви не знаєте, коли (дається автоматичне вивезення сміття), а за необхідності контекст все ще є (він, можливо, вже був зібраний). Тож безпечніше забезпечити послідовне стан іншими способами, і можна захотіти змусити програміста до цього.