我正在努力完全掌握所有权转移过程中内存部分会发生什么。 如果一个值由一个变量拥有并转移到另一个变量,则转移后原始变量的堆栈帧中的内存会发生什么情况
举个例子,t超出了范围,但测试仍然有效。 Test(1) 存储在哪里,如果它在堆栈中创建,那么在块结束后它如何仍然有效?
struct Test(u8);
impl Drop for Test {
fn drop(&mut self) {
println!("{} is dropped", self.0);
}
}
fn main() {
let test;
{
println!("step 1");
let t = Test(1);
println!("step 2");
test = t;
}
println!("{}", test.0);
}
输出:
step 1
step 2
1
1 is dropped
当所有者超出范围时,Rust 通过回收内存自动清理与该所有者关联的数据。 这是一个似乎与之矛盾的例子:
fn main() {
println!("step 1");
let test = create_struct();
println!("step 2");
println!("{}", test.0);
}
pub fn create_struct() -> Test {
Test(1)
}
输出:
step 1
step 2
1
1 is dropped
如果当所有者超出范围时回收内存,那么从函数返回值如何防止这种情况发生?
从第一个示例的输出来看,它没有被复制,因为只删除了一个 Test 实例,这也意味着堆栈内存没有在内部块中回收,或者这里发生了什么?
免责声明:由于优化,内存中实际发生的情况很难确定。例如,变量根本不需要存储在内存中,它可以存储在 CPU 寄存器中。这个答案的其余部分假设变量以“明显”的方式存储在内存中。
如果一个值由一个变量拥有并转移到另一个变量,则转移后原始变量的堆栈帧中的内存会发生什么情况
它保持未使用状态(或通过优化重新用于存储其他变量)。
举个例子,t超出了范围,但测试仍然有效。 Test(1) 存储在哪里,如果它在堆栈中创建,那么在块结束后它如何仍然有效?
它首先存储在
t
中,然后移动(按位复制)到test
。移动后,t
中的记忆不再相关。
如果当所有者超出范围时回收内存,那么从函数返回值如何防止这种情况发生?
它通过将值移动到另一个位置来防止这种情况。如果你只是调用
create_struct();
而不将值分配给任何东西,它确实会被丢弃。通过将其分配给变量,可以有效地延长其寿命。
从第一个示例的输出来看,它没有被复制,因为只删除了一个 Test 实例
这是正确的 - 它没有被复制,而是被移动了。与 C++ 不同,Rust 不执行隐式复制,您必须显式调用
.clone()
,然后移动 that 值。
这也意味着堆栈内存没有在内部块中回收,或者这里发生了什么?
函数返回后,堆栈内存就会被回收。在此之前,由于堆栈的工作原理,移动或删除值不会回收内存。