Rust有什么而不​​是垃圾收集器?

rix*_*rix 77 rust

我理解Rust没有垃圾收集器,并且想知道当绑定超出范围时如何释放内存.

所以在这个例子中,我理解Rust在超出范围时回收分配给'a'的内存.

{
    let a = 4
}
Run Code Online (Sandbox Code Playgroud)

我遇到的问题,首先是如何发生这种情况,其次这不是一种垃圾收集?它与"典型"垃圾收集有何不同?

Ayo*_*nix 60

垃圾收集通常定期或按需使用,例如堆接近满或高于某个阈值.然后它会查找未使用的变量并释放其内存,具体取决于算法.

Rust会知道变量何时超出范围或其生命周期在编译时结束,因此插入相应的LLVM /汇编指令以释放内存.

Rust还允许某种垃圾收集,例如原子引用计数.


Mat*_* M. 38

无论策略如何,管理程序中资源(包括内存)的基本思想是可以回收与无法访问的"对象"相关的资源.超越内存,这些资源可以是互斥锁,文件句柄,套接字,数据库连接......

带有垃圾收集器的语言会定期扫描内存(以这种或那种方式)查找未使用的对象,释放与之关联的资源,最后释放这些对象使用的内存.

Rust没有GC,它如何管理?

Rust拥有所有权.使用仿射类型系统,它跟踪哪个变量仍然保持在一个对象上,当这样的变量超出范围时,调用它的析构函数.您可以非常轻松地看到仿射类型系统:

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

产量:

<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;
                     ^
Run Code Online (Sandbox Code Playgroud)

这完美地说明了在任何时间点,在语言层面,都会跟踪所有权.

这个作品的所有权递归:如果你有一个Vec<String>(即动态字符串数组),那么每个String由拥有Vec其本身是由一个变量或其他物体,拥有等等......因此,当变量超出范围,它递归地释放了它所拥有的所有资源,甚至间接地释放了它.在这种情况下,Vec<String>这意味着:

  1. 释放与每个相关联的内存缓冲区 String
  2. 释放与其Vec自身关联的内存缓冲区

因此,由于所有权跟踪,所有程序对象的生命周期严格依赖于一个(或几个)函数变量,这些函数变量最终将超出范围(当它们所属的块结束时).

注意:这有点乐观,使用引用计数(RcArc)可能形成引用循环,从而导致内存泄漏,在这种情况下,与循环相关的资源可能永远不会被释放.

  • “我不认为引用计数是一个完整的垃圾收集机制,因为它必须得到补充以避免循环泄漏”。RC 通常被认为是 GC 的一种形式。例如,在 Mathematica 和 Erlang 中,循环无法通过设计创建,因此 RC 不会泄漏。高级视角,参见“垃圾收集的统一理论” https://www.cs.virginia.edu/~cs415/reading/bacon-garbage.pdf (3认同)
  • “我看不出定期不涵盖增量情况”。例如,停止世界算法将被视为周期性,而三色标记被视为增量。在这种情况下,它们是对立的。 (3认同)
  • “带有垃圾收集器的语言会定期扫描内存(一种或另一种方式)”。许多人这样做,但总体而言并非如此。实时垃圾收集器以增量方式扫描而不是定期扫描。像 Mathematica 这样的引用计数语言根本不扫描。 (2认同)
  • @JD 你陷得太深了。他的解释与 GC 工作原理无关,只涉及 GC 和非 GC 语言之间的差异。您尝试实现的差异化基于 GC 本身的实现。他试图在抽象意义上区分 GC。在此上下文中,无需深入研究 500 个单词来了解“周期性”的语义含义。 (2认同)

Swi*_*iss 6

使用必须手动管理内存的语言,堆栈和堆之间的区别变得至关重要.每次调用函数时,都会在堆栈上为该函数范围内包含的所有变量分配足够的空间.当函数返回时,与该函数关联的堆栈帧从堆栈"弹出",并释放内存以供将来使用.

从实际角度来看,这种无意的内存清理被用作自动存储器存储的一种方法,它将在功能范围结束时被清除.

这里有更多信息:https: //doc.rust-lang.org/book/the-stack-and-the-heap.html

  • 虽然使用堆栈很方便,但如果所有值都是"在堆上创建的",仍然可以处理确定性对象生命周期.因此它是一个实现细节; 不一定是语言策略. (3认同)
  • 你一直在用这个词。我不认为这意味着你认为它意味着什么。 (2认同)