Я понимаю, что в Rust нет сборщика мусора, и мне интересно, как освобождается память, когда привязка выходит за рамки.
Итак, в этом примере я понимаю, что Rust освобождает память, выделенную для 'a', когда она выходит за пределы области видимости.
{
let a = 4
}
Проблема, с которой я столкнулся, во-первых, как это происходит, а во-вторых, разве это не сборка мусора? Чем он отличается от «типичной» сборки мусора?
Ответы:
Сборка мусора обычно используется периодически или по запросу, например, если куча почти заполнена или превышает некоторый порог. Затем он ищет неиспользуемые переменные и освобождает их память в зависимости от алгоритма .
Rust будет знать, когда переменная выходит за пределы области видимости или ее время жизни заканчивается во время компиляции, и, таким образом, вставляет соответствующие инструкции LLVM / сборки для освобождения памяти.
Rust также допускает некоторую сборку мусора, например, атомарный подсчет ссылок .
источник
new()
функции, такой как C, это просто статические функции, и, в частности, что-то вродеlet x = MyStruct::new()
создания своего объекта в стеке. Реальный показатель кучного распределения являетсяBox::new()
(или какой - либо из структур , которые зависят от Box).Основная идея управления ресурсами (включая память) в программе, независимо от стратегии, заключается в том, что ресурсы, связанные с недостижимыми «объектами», могут быть возвращены. Помимо памяти, этими ресурсами могут быть блокировки мьютексов, дескрипторы файлов, сокеты, соединения с базой данных ...
Языки со сборщиком мусора периодически сканируют память (так или иначе), чтобы найти неиспользуемые объекты, освободить связанные с ними ресурсы и, наконец, освободить память, используемую этими объектами.
В Rust нет сборщика мусора, как он справляется?
У Rust есть право собственности. Используя систему аффинных типов , он отслеживает, какая переменная все еще хранится в объекте, и, когда такая переменная выходит за пределы области видимости, вызывает его деструктор. Вы можете легко увидеть, как действует система аффинных типов:
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>
этим означает:String
Vec
самим собойТаким образом, благодаря отслеживанию владения время жизни ВСЕХ программных объектов строго привязано к одной (или нескольким) функциональным переменным, которые в конечном итоге выйдут за пределы области видимости (когда блок, которому они принадлежат, завершится).
Примечание: это немного оптимистично, используя подсчет ссылок (
Rc
илиArc
) можно формировать циклы ссылок и, таким образом, вызывать утечки памяти, и в этом случае ресурсы, привязанные к циклу, могут никогда не быть освобождены.источник
В языке, где необходимо вручную управлять памятью, различие между стеком и кучей становится критическим. Каждый раз, когда вы вызываете функцию, в стеке выделяется достаточно места для всех переменных, содержащихся в области действия этой функции. Когда функция возвращается, кадр стека, связанный с этой функцией, «выталкивается» из стека, а память освобождается для использования в будущем.
С практической точки зрения эта непреднамеренная очистка памяти используется как средство автоматического сохранения памяти, которая будет очищена в конце области действия функции.
Дополнительная информация доступна здесь: https://doc.rust-lang.org/book/the-stack-and-the-heap.html
источник