When is the memory get freed?

Hi. Im just start to learning rust. And i have confusions about ownership.
In the code below, when is memory that stores "2222" get freed ?
At the end of the main, end of the do_something or just after the assignment (*new_str = s) ?

fn main() {
    let s: String = String::from("1111");
    let mut new_str: String = String::from("2222");
    println!("{}", s);
    do_something(s, &mut new_str);
    println!("{}", new_str);
}

fn do_something(s: String, new_str: &mut String) {
    println!("{}", new_str);
    *new_str = s;
    println!("{}", new_str);
}

in this particular example, it is the line

modify the value through a mut reference counts as an assignment expression, and an assignment has the semantic of dropping the old value. see the reference here:
https://doc.rust-lang.org/reference/expressions/operator-expr.html#basic-assignments

1 Like

There's actually two copies of 2222 here. The first is the literal "2222", which is stored in the program binary and not freed until the OS cleans up the program; the other has a more complicated journey. It starts on this line, which makes a copy of the literal, places it on the heap in a new allocation, and stores a pointer to that heap allocation within the String structure on the stack:

let mut new_str: String = String::from("2222");

You then make a mutable reference to the String, which in turn still contains a pointer to the heap allocation and pass that into do_something:

do_something(s, &mut new_str);

This, in turn takes a different String value (pointing to a different heap allocation) and overwrites the original String:

*new_str = s;

Immediately before the write actually happens, the original String value is dropped because it is no longer reachable— &mut references guarantee that there is no other way to access the value that they point at.

String doesn't have a Drop implementation itself, but contains a Vec<u8> which actually manages the heap allocation. This gets dropped as part of the process of dropping the String, and Vec does implement Drop, which drops all of the elements in the vector, but doesn't yet free the heap memory. Vec contains a field of type RawVec which gets dropped after Vec::drop() is run, and it's RawVec's Drop implementation that actually frees the heap memory that contains 2222.

The memory for the String struct itself is reused to hold the newly-assigned String, and will be dropped when the variable new_str leaves scope at the end of main, freeing the memory for 1111 by a similar process.


For a more detailed explanation of how all this works under the hood, the Nomicon contains a chapter describing how Vec works in detail. From a user's perspective, however, you just need to remember that assigning to a place that's already occupied will drop whatever was there before the assignment, as @nerditation says.

5 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.