Що має Руст замість збирача сміття?


95

Я розумію, у Rust немає збирача сміття, і мені цікаво, як звільняється пам’ять, коли прив’язка виходить за рамки.

Отже, у цьому прикладі я розумію, що Руст повертає пам’ять, виділену для а, коли вона виходить за межі обсягу.

{
    let a = 4
}

Проблема, з якою я маю з цим, полягає, по-перше, у тому, як це відбувається, а по-друге, чи це не свого роду збір сміття? Чим він відрізняється від «типового» вивезення сміття?


12
"Детермінований час життя об'єкта". Подібно до C ++.
користувач2864740

@ user2864740 Цей посібник застарів. Сучасна заміна, мабуть, буде doc.rust-lang.org/book/references-and-borrowing.html .
Veedrac

Відповіді:


74

Збір сміття зазвичай використовується періодично або на вимогу, наприклад, якщо купа близька до повної або перевищує певний поріг. Потім він шукає невикористані змінні та звільняє їх пам’ять, залежно від алгоритму .

Руст знав би, коли змінна виходить за межі обсягу або час її життя закінчується під час компіляції, і таким чином вставляє відповідні інструкції LLVM / збірки, щоб звільнити пам’ять.

Іржа також дозволяє збирати сміття, наприклад, підрахунок атомних посилань .


Виділяючи пам’ять при введенні змінних та звільняючи пам’ять, коли пам’ять більше не потрібна? Я насправді не знаю, що ви хочете сказати цим. Можливо, тоді ми маємо різні думки щодо того, що таке ГХ.
Ayonix

1
Його питання полягає в тому, чим підхід Руста відрізняється від типового GC. Тож я пояснив, що таке ГХ і як Руст робить це без ГХ.
Ayonix

1
doc.rust-lang.org/book/the-stack-and-the-heap.html пояснює це досить добре. Так, багато речей є у стосі, але не кажучи вже про недостатній показник (див. Вставку). Я пропустив це заради простоти, оскільки питання ставилося загалом
Ayonix

1
@Amomum Actually Rust не має жодної помазаної new()функції, такої як C, це просто статичні функції, і зокрема щось подібне let x = MyStruct::new()створює свій об'єкт у стеку. Реальний показник кучного розподілу є Box::new()(або який - або з структур , які залежать від Box).
Маріо Карнейро

1
Які ще мови обробляють управління пам'яттю подібним чином до Rust?
still_dreaming_1

43

Основна ідея управління ресурсами (включаючи пам’ять) у програмі, незалежно від стратегії, полягає в тому, що ресурси, прив’язані до недосяжних «об’єктів», можуть бути повернені. Окрім пам'яті, цими ресурсами можуть бути замки мьютексу, дескриптори файлів, сокети, підключення до бази даних ...

Мови за допомогою збирача сміття періодично сканують пам’ять (так чи інакше), щоб знайти невикористані об’єкти, звільнити пов’язані з ними ресурси та, нарешті, звільнити пам’ять, що використовується цими об’єктами.

Руст не має ГХ, як він управляється?

Іржа має право власності. Використовуючи систему афінного типу , він відстежує, яка змінна все ще тримається на об’єкті, і коли така змінна виходить за межі області дії, викликає її деструктор. Ви можете побачити діючу систему афінного типу досить легко:

fn main() {
    let s: String = "Hello, World!".into();
    let t = s;
    println!("{}", s);
}

Урожайність:

<anon>:4:24: 4:25 error: use of moved value: `s` [E0382]
<anon>:4         println!("{}", s);

<anon>:3:13: 3:14 note: `s` moved here because it has type `collections::string::String`, which is moved by default
<anon>:3         let t = s;
                     ^

що чудово ілюструє, що в будь-який момент часу, на мовному рівні, відстежується право власності.

Це право власності працює рекурсивно: якщо у вас є Vec<String>(тобто динамічний масив рядків), то кожна з Stringних належить тій, Vecяка сама належить змінній чи іншому об’єкту тощо ... отже, коли змінна виходить за межі області дії, це рекурсивно звільняє всі наявні у нього ресурси, навіть побічно. У випадку з Vec<String>цим означає:

  1. Вивільнення буфера пам'яті, пов'язаного з кожним String
  2. Звільнення буфера пам'яті, пов'язаного з самим Vecсобою

Таким чином, завдяки відстеженню власності, термін служби ВСІХ програмних об’єктів суворо прив’язаний до однієї (або кількох) функціональних змінних, які в кінцевому підсумку вийдуть за межі обсягу (коли закінчується блок, якому вони належать).

Примітка: це трохи оптимістично, за допомогою підрахунку посилань ( Rcабо Arc) можна формувати цикли посилань і, таким чином, спричиняти витік пам'яті, і в цьому випадку ресурси, прив’язані до циклу, ніколи не можуть бути звільнені.


2
Msgstr "Мови з колектором сміття періодично сканують пам'ять (так чи інакше)". Багато хто робить, але це неправда загалом. Сміттєзбирачі в реальному часі сканують поступово, а не періодично. Мови підрахунку посилань, такі як Mathematica, взагалі не скануються.
JD

@JonHarrop: Я не вважаю підрахунок посилань повним механізмом збору сміття, оскільки він повинен бути доповнений, щоб уникнути циклів витоків. Що стосується інкрементної / періодичної різниці, це може бути моє погане володіння англійською мовою, але я не бачу, як періодичний не охоплює інкрементний регістр ... Я думаю, що біт "(так чи інакше)" адекватно передає, що багато різних підходи існують. У будь-якому випадку, якщо у вас є кращий спосіб стисло описати збір сміття, будь ласка, підкажіть. Однак я не маю наміру висловлюватися в повному обсязі пояснень: я некваліфікований для цього.
Matthieu M.

1
"Я не вважаю підрахунок посилань повним механізмом збору сміття, оскільки він повинен бути доповнений, щоб уникнути циклів витоків". RC традиційно розглядається як форма GC. Наприклад, в Mathematica та Erlang цикли не можуть бути створені за проектом, тому RC не витікає. Для перспективи високого рівня див. "Єдина теорія збору сміття" cs.virginia.edu/~cs415/reading/bacon-garbage.pdf
JD

@JonHarrop: Правда, якщо жоден цикл неможливий, то RC не може витікати.
Матьє М.

2
Msgstr "Я не бачу, як періодичний не охоплює додатковий регістр". Зупинити світові алгоритми буде розглядатися як періодичний, тоді як триколірне маркування, наприклад, розглядається як додаткове. У цьому контексті вони протилежні.
JD

6

З мовою, де вам потрібно керувати пам'яттю вручну, різниця між стеком і купою стає критичною. Кожного разу, коли ви викликаєте функцію, у стеку виділяється достатньо місця для всіх змінних, що містяться в області дії цієї функції. Коли функція повертається, кадр стека, пов'язаний з цією функцією, "вискакує" зі стеку, і пам'ять звільняється для подальшого використання.

З практичної точки зору це ненавмисне очищення пам'яті використовується як засіб автоматичного зберігання пам'яті, яке буде очищено в кінці області дії функції.

Додаткову інформацію можна отримати тут: https://doc.rust-lang.org/book/the-stack-and-the-heap.html


3
Незважаючи на те, що використання стека зручно, детерміновані періоди життя об’єкта все ще можуть оброблятися, якщо всі значення були «створені в купі». Таким чином, це деталь реалізації; не обов'язково мовна стратегія.
користувач2864740

2
Ви продовжуєте використовувати це слово. Я не думаю, що це означає те, що ви думаєте.
швейцарський

Означає те, що я хочу висловити ; будучи протилежністю недетермінованому життю. Зробіть пропозицію для кращої фрази.
user2864740

Дякую за відповідь, я дав бали першому просто тому, що його було подано першим. Інформація така ж корисна і достовірна.
rix

@ user2864740 Детермінований час життя об’єкта означає можливість точно визначити, коли пам’ять об’єкта буде очищена, як тільки буде викликаний його деструктор. Це не має нічого спільного з тим, як спочатку називається цей деструктор. Ви постійно повторюєте один і той самий термін, хоча це не має прямого значення для питання.
швейцарський
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.