Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/rust/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在某一天移动对象的过程中,Rust能否优化位拷贝?_Rust_Move Semantics_Llvm Codegen - Fatal编程技术网

在某一天移动对象的过程中,Rust能否优化位拷贝?

在某一天移动对象的过程中,Rust能否优化位拷贝?,rust,move-semantics,llvm-codegen,Rust,Move Semantics,Llvm Codegen,考虑一下这个片段 struct Foo { dummy: [u8; 65536], } fn bar(foo: Foo) { println!("{:p}", &foo) } fn main() { let o = Foo { dummy: [42u8; 65536] }; println!("{:p}", &o); bar(o); } 该计划的一个典型例子是 0x7fffc1239890 0x7fffc1229890 地址不同的地

考虑一下这个片段

struct Foo {
    dummy: [u8; 65536],
}

fn bar(foo: Foo) {
    println!("{:p}", &foo)
}

fn main() {
    let o = Foo { dummy: [42u8; 65536] };
    println!("{:p}", &o);
    bar(o);
}
该计划的一个典型例子是

0x7fffc1239890
0x7fffc1229890
地址不同的地方

显然,大数组
dummy
已被复制,正如编译器的move实现中所预期的那样。不幸的是,这可能会对性能产生不小的影响,因为
dummy
是一个非常大的数组。这种影响会迫使人们选择通过引用传递参数,即使函数实际上在概念上“使用”了参数

由于
Foo
不派生
Copy
,对象
o
被移动。由于锈蚀禁止访问移动的对象,是什么阻止
bar
“重用”原始对象
o
,迫使编译器生成一个可能昂贵的逐位拷贝?有没有一个根本性的困难,或者有一天我们会看到编译器优化掉这个按位复制吗?

考虑到在Rust中(与C或C++不同),值的地址并不重要,从语言的角度来看,没有任何东西可以阻止省略复制

然而,现在rustc并没有优化任何东西:所有的优化都委托给LLVM,而且似乎您在这里遇到了LLVM优化器的一个限制(不清楚这个限制是由于LLVM接近C的语义还是仅仅是一个遗漏)

因此,有两种改进代码生成的方法:

  • 教LLVM执行此优化(如果可能)
  • 教rustc执行此优化(现在rustc已经有了MIR,优化过程将传递给它)

但现在,您可能只想避免在堆栈上分配如此大的对象,例如,您可以
Box
it。

Rustc确实优化了移动。在本例中它没有这样做,可能是因为llvm没有内联条。这甚至可能是因为您试图观察指针值,而llvm不确定优化是否安全。我在没有打印
:p
的情况下尝试了它,并改用test::black\u框,副本从程序集中消失。@Manishearth
正在内联。LLVM在删除大型阵列的移动方面非常糟糕。
NRVO
标记的问题与此相关:在这种情况下是否保证
o
丢弃?鉴于它被移出到
bar()
,那么
o
内存的释放点是什么?说到MIR优化过程,第一个是简单的移动目标传播过程:。跟踪问题是。与其只是避免堆栈分配,不如假设移动将得到优化,如果没有优化,则只在以后装箱。在《铁锈》中,大多数时候你不应该考虑避免抄袭。@MichaelYounkin:我部分同意。问题是,在堆栈上复制几次大型对象很容易导致堆栈溢出,特别是在没有进行优化的调试目标中。如果缓冲区非常大,那么动态分配的成本应该比初始化缓冲区本身的成本要小得多。@MatthieuM在堆上分配它非常好,但根据我的经验,即使是writing Box::new(BigStruct::new())也会先在堆栈中分配BigStruct(在BigStruct::new中),然后在堆中复制它(在框中::新建)。还是我遗漏了什么?@Pierre Antoine:在调试中,是的,现在;这就是为什么如此受欢迎的原因。在发行版中,堆栈副本应该希望得到优化,但这可能会导致调试中的堆栈溢出,阻止您测试代码:(