当一个堆栈分配的值被装箱时会发生什么?

8
如果我们有一个已经在堆栈上分配的值,那么装箱会将其复制到堆中并转移所有权吗(这是在.NET中工作的方式,但两个副本都将保持活动状态除外)?或者编译器是否足够“聪明”,从一开始就直接在堆上分配它?
struct Foo {
    x: i32,
}

fn main() {
    // a is allocated on stack?
    let a = Foo { x: 1 };

    // if a is not used, it will be optimized out
    println!("{}", a.x);

    // what happens here? will the stack allocated structure
    // be moved to heap? or was it originally allocated on heap?
    let b = Box::new(a);
}

我不是汇编语言专家,但这看起来似乎是在堆栈上分配的,然后移动:http://pastebin.com/8PzsgTJ1。但我需要得到一个确切知道发生了什么的人的确认。

2个回答

5
这种优化方式是相当奇怪的。例如,在以下代码中:
let a = Foo { x: 1 };
// operation that observes a
let b = Box::new(a);
// operation that observes b

&a&b将会是相等的,这可能令人惊讶。然而,如果你做类似的事情,但不观察a

#[inline(never)]
fn frobnotz() -> Box<Foo> {
    let a = Foo { x: 1 };
    Box::new(a)
}

你可以通过LLVM IR看到,这个案例已经被优化了:
define internal fastcc noalias dereferenceable(4) %Foo* @_ZN8frobnotz20h3dca7bc0ee8400bciaaE() unnamed_addr #0 {
entry-block:
  %0 = tail call i8* @je_mallocx(i64 4, i32 0)
  %1 = icmp eq i8* %0, null
  br i1 %1, label %then-block-106-.i.i, label %"_ZN5boxed12Box$LT$T$GT$3new20h2665038481379993400E.exit"

then-block-106-.i.i:                              ; preds = %entry-block
  tail call void @_ZN3oom20he7076b57c17ed7c6HYaE()
  unreachable

"_ZN5boxed12Box$LT$T$GT$3new20h2665038481379993400E.exit": ; preds = %entry-block
  %2 = bitcast i8* %0 to %Foo*
  %x.sroa.0.0..sroa_idx.i = bitcast i8* %0 to i32*
  store i32 1, i32* %x.sroa.0.0..sroa_idx.i, align 4
  ret %Foo* %2
}

同样地,你可以在堆栈上返回结构体,然后将其打包,仍然只有一个分配:

你可能认为这会给我们带来可怕的性能问题:返回一个值然后立即将其打包?!这不是最糟糕的模式吗?Rust比那更聪明。这段代码中没有复制。main函数为盒子分配了足够的空间,将指向该内存的指针传递给foo作为x,然后foo直接将值写入Box中。


谢谢你详细的回答和链接。我原以为没有必要阅读Rust书中的“不稳定”部分,但我错了。 - Sergii Bogomolov

3

正如 Rust 官方文档所解释的Box<T>::new(x: T) 在堆上分配内存,然后将参数移动到该内存中。在 let b = Box::new(a) 后访问 a 将导致编译时错误。


这正是我想知道的。像往常一样,这是个RTFM问题 :) - Sergii Bogomolov
1
@SergiiBogomolov:不要为此感到难过,学习如何浏览新文档需要时间(特别是当它不断变化时)。 - Matthieu M.
3
为了澄清,编译器可以对这种情况进行优化(如我的答案所述),但前提是“栈分配”的值立即被移动到“Box”中。如果在移动到“Box”之前使用该值,则不会进行优化。 - Shepmaster
这意味着从堆栈到堆的是逐字节的复制吗? - Ashika Umanga Umagiliya

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