我知道Rust没有垃圾收集器,并且想知道当绑定超出范围时如何释放内存。
因此,在此示例中,我了解到Rust超出范围时,Rust回收分配给“ a”的内存。
{
let a = 4
}
我遇到的问题是,首先是如何发生的,其次,这不是一种垃圾收集吗?它与“典型”垃圾收集有何不同?
我知道Rust没有垃圾收集器,并且想知道当绑定超出范围时如何释放内存。
因此,在此示例中,我了解到Rust超出范围时,Rust回收分配给“ a”的内存。
{
let a = 4
}
我遇到的问题是,首先是如何发生的,其次,这不是一种垃圾收集吗?它与“典型”垃圾收集有何不同?
Answers:
new()
像C这样的受膏函数,它们只是静态函数,尤其是let x = MyStruct::new()
在堆栈上创建其对象的东西。堆分配的真正指标是Box::new()
(或任何依赖Box的结构)。
无论采用何种策略,在程序中管理资源(包括内存)的基本思想是可以回收与无法访问的“对象”相关的资源。除了内存之外,这些资源还可以是互斥锁,文件句柄,套接字,数据库连接...
具有垃圾回收器的语言会定期(一种或另一种方式)扫描内存以查找未使用的对象,释放与它们关联的资源,最后释放那些对象使用的内存。
Rust没有GC,它如何管理?
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