我认为,一旦移动了一个对象,它在堆栈上占用的内存就可以用于其他目的.然而,下面的最小示例显示了相反的情况.
#[inline(never)]
fn consume_string(s: String) {
drop(s);
}
fn main() {
println!(
"String occupies {} bytes on the stack.",
std::mem::size_of::<String>()
);
let s = String::from("hello");
println!("s at {:p}", &s);
consume_string(s);
let r = String::from("world");
println!("r at {:p}", &r);
consume_string(r);
}
编译带有--release
标志的代码后,它在我的计算机上给出以下输出.
String occupies 24 bytes on the stack.
s at 0x7ffee3b011b0
r at 0x7ffee3b011c8
很明显,即使移动了s
,r
也不会重用堆栈上最初属于s
的24字节块.我认为重用移动对象的堆栈内存是安全的,但Rust编译器为什么不这样做呢?我是不是错过了什么角落的案子?
更新:
#[inline(never)]
fn consume_string(s: String) {
drop(s);
}
fn main() {
println!(
"String occupies {} bytes on the stack.",
std::mem::size_of::<String>()
);
{
let s = String::from("hello");
println!("s at {:p}", &s);
consume_string(s);
}
let r = String::from("world");
println!("r at {:p}", &r);
consume_string(r);
}
上面的代码给出了下面的输出.
String occupies 24 bytes on the stack.
s at 0x7ffee2ca31f8
r at 0x7ffee2ca31f8
我认为花括号不应该有任何区别,因为s
的生存期在调用comsume_string(s)
后结束,其丢弃处理程序在comsume_string()
内调用.为什么添加花括号可以实现优化?
下面给出了我使用的Rust编译器的版本.
rustc 1.54.0-nightly (5c0292654 2021-05-11)
binary: rustc
commit-hash: 5c029265465301fe9cb3960ce2a5da6c99b8dcf2
commit-date: 2021-05-11
host: x86_64-apple-darwin
release: 1.54.0-nightly
LLVM version: 12.0.1
更新2:
- 这是一个无效的优化.在某些情况下,如果我们执行"优化",编译的代码可能会失败.
- 这是一个有效的优化,但编译器(包括rustc前端和llvm)无法执行它.
- 这是一个有效的优化,但暂时关闭,如this.
- 这是一个有效的优化,但没有实现.它将在future 添加.