为什么Rust会重复使用具有相同值的内存

4

示例代码:

fn main() {
    let mut y = &5; // 1

    println!("{:p}", y);

    {
        let x = &2; // 2
        println!("{:p}", x);
        y = x;
    }

    y = &3; // 3
    println!("{:p}", y);
}

如果第三个任务包含 &3,则代码输出:
0x558e7da926a0
0x558e7da926a4
0x558e7da926a8

如果第三个赋值包含&2(与第二个赋值相同),则代码输出:
0x558e7da926a0
0x558e7da926a4
0x558e7da926a4

如果第三个变量包含&5(与第一个变量相同),则代码输出:
0x558e7da926a0
0x558e7da926a4
0x558e7da926a0

为什么Rust不释放内存,而是在赋值相同的情况下重复使用它,否则分配一个新的内存块?

为什么要分配更多的内存,当相同的内存可以安全地重复使用呢? - Thilo
@Thilo,我也这么认为,但Rust为什么要这样做呢?我认为在第二次和第三次赋值后,Rust可以释放内存。 - TupleCats
3
如果没有更重要的东西需要存储,那么在栈上释放一个变量并稍后用相同的值重新分配它是没有好处的。这个功能按照预期工作。 - Simson
系统语言的第一条规则是,不要假设任何东西。 - Stargateur
这个回答解决了你的问题吗?为什么我可以返回一个指向本地字面量的引用,但不能返回一个变量的引用?(https://dev59.com/z1UL5IYBdhLWcg3wb3pz) - Boiethios
显示剩余3条评论
2个回答

5

相同的字面量数值出现两次是无法区分的。你不能期望两个字面量的地址是相同的,也不能期望它们是不同的。

这允许编译器(但实际上可以选择其他方式)在可执行代码中发出一个5数据,并将所有&5引用它。常量还可能(见注释)具有静态生存期,在此情况下它们不会在程序执行期间分配/释放,它们总是被分配。


2
常量可能会被提升为静态变量,但一般来说它们也可能成为临时变量或完全被编译器优化掉。这里的5得到了静态提升处理,因为代码明确地取其地址;如果不是这样的话,编译器可以自由地将其创建在寄存器中或者优化掉它的存在,而根本不会出现任何5的二进制形式。 - trent
1
@trentcl 我认为这是有保证的,请参见 https://dev59.com/z1UL5IYBdhLWcg3wb3pz - Boiethios
1
@FrenchBoiethios 这是有保证的,因为地址被占用了,但通常情况下常量不会被静态提升。我之前的评论是为了澄清先前答案的措辞,这可能被误解为所有常量都被提升为静态变量,这是不正确的。 - trent
2
@trentcl:实际上,如果编译器能够省略地址(如在let x = &5; println!("{}", 1 + * x);等代码中),那么我不会感到惊讶它并不是保证的。因此,我不期望在二进制数据段中找到一个字面量5,而是期望直接嵌入汇编语言中的一个6 - Matthieu M.

4

优化编译器可以使用许多技巧来确定变量是否可以分配常量值。您的发现与此一致,如果不需要运行重复的代码,则无需运行。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接