Search code examples
rustownership

What happens in memory when ownership transfer happens


Im struggling to fully grasp what happens to the memory part during ownership transfer. if a value is owned by one variable and transferred to another, what happens to the memory in the original variable's stack frame after the transfer

As an example, t is out of scope, but test still works. Where is Test(1) stored, and how is it still valid after the block ends if its created in the stack?

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);
}

output:

step 1
step 2
1
1 is dropped

When an owner goes out of scope, Rust automatically clean-up the data associated with that owner by reclaiming memory. Here's an example that seems to contradict it:

fn main() {
   println!("step 1");
   let test = create_struct();
   println!("step 2");
   println!("{}", test.0);
}

pub fn create_struct() -> Test {
   Test(1)
}

output:

step 1 
step 2 
1 
1 is dropped 

If memory is reclaimed when an owner goes out of scope, how does returning a value from a function prevent this?

Judging from the output of the first example, it's not copied because only one instance of Test was dropped, also that means the stack memory wasn't reclaimed in the inner block or what is happening here?


Solution

  • Disclaimer: what actually happens in memory is difficult to pinpoint due to optimizations. For example, a variable doesn't need to be stored in memory at all, it could be in a CPU register. The remainder of this answer assumes that the variables are stored in memory in the "obvious" way.

    if a value is owned by one variable and transferred to another, what happens to the memory in the original variable's stack frame after the transfer

    It remains unused (or gets reused for storing other variables, with optimization).

    As an example, t is out of scope, but test still works. Where is Test(1) stored, and how is it still valid after the block ends if its created in the stack?

    It is first stored in t, then moved (bitwise-copied) to test. After the move, the memory in t is no longer relevant.

    If memory is reclaimed when an owner goes out of scope, how does returning a value from a function prevent this?

    It prevents this by moving the value to another location. If you just called create_struct(); without assigning the value to anything, it would indeed get dropped. By assigning it to a variable, you effectively extend its life.

    Judging from the output of the first example, it's not copied because only one instance of Test was dropped

    That's correct - it wasn't copied, it was moved. Unlike C++, Rust doesn't do implicit copies, you have to call .clone() explicitly, and then that value is moved.

    also that means the stack memory wasn't reclaimed in the inner block or what is happening here?

    The stack memory gets reclaimed once the function returns. Before that, moving or dropping the value doesn't reclaim the memory due to how stack works.