1

I have seen a build function called drop(T) in rust, basically, it moves the given variable.

let's say if we have code as follow:

struct Obj {
    a: i32,
}

impl Drop for Obj {
    fn drop(&mut self) {
        println!("> Dropping {}", self.a);
    }
}

fn main() {
    let mut m = &Obj { a: 5 };

    m = &Obj { a: 6 };
    m = &Obj { a: 7 };
    m = &Obj { a: 8 };

    let t = thread::spawn(|| {
        for i in 0..5 {
            println!("Counting {}", i);
            thread::sleep(Duration::from_secs_f32(1.0));
        }
    });
    t.join().unwrap();
}

The Result is :

> Dropping 6
> Dropping 7
> Dropping 8
Counting 0
Counting 1
Counting 2
Counting 3
Counting 4
> Dropping 5

As the result shows the 6 to 8 has been collected just after resignments, the origin 5 is lasting until the end of main. why the 5 is not collected in the first place?

En Xie
  • 510
  • 4
  • 19
  • 2
    Everything owned in the scope is droped ("cleaned") when its scope ends. – Netwave Dec 20 '21 at 12:09
  • @Netwave in the case of code, can I clean the Obj{5} by hand before the end of main – En Xie Dec 20 '21 at 12:12
  • @Netwave that's not going to compile, you can't move out of a rerference. – Masklinn Dec 20 '21 at 12:15
  • @EnXie you can if you keep it named (as is, it's an anonymous temporary) and drop all its references beforehand, but that's not going to do anything useful since it doesn't implement `Drop`. – Masklinn Dec 20 '21 at 12:16
  • @Masklinn, yeah, I was actually building the proper answer. – Netwave Dec 20 '21 at 12:17
  • @Masklinn if I keep changing the pointer 'm' to some other new &Obj , as long as the program running. Are there will be a lot of older Objs in memory, if so how long it will last ? – En Xie Dec 20 '21 at 12:24
  • @EnXie depends on the decision of the optimiser. Semantically until the end of the stackframe, but practically the stack allocator could decide to reuse older and now-dead locations. Now sure whether or how much llvm bothers with that. – Masklinn Dec 20 '21 at 13:07
  • The duplicate and existing answers don't really explain the drop behavior here. Essentially `m = &...;` doesn't do what you want, it assigns a reference to `m` but the `...` is immediately dropped. You'll see the compiler yield an error if you actually tried to use `m`. The `let m = &...;` is actually slightly different and persists the `...` until the end of the scope. Perhaps, OP, you should ask a fresh question with that as the focus if you're interested in more details. – kmdreko Dec 20 '21 at 17:51

3 Answers3

3

I think compiler will insert code like this

fn main() {
    let mut _1 = Obj { a: 5 };
    let mut m = &_1;
    let mut _2 = Obj { a: 6 };
    m = &_2;

    drop(_1);
    drop(_2);
}

so origin Obj will drop when exit main scope

mxp-xc
  • 456
  • 2
  • 6
  • I have tried the Drop Traits.. something interesting happened, do you know how it works? – En Xie Dec 20 '21 at 13:00
  • I don’t know how it works. I just remember reading a book before, introducing direct reference, the compiler will create a temporary variable after compilation, and then the temporary variable is manipulated by the compiler. But I don’t know what the compiler will do with it – mxp-xc Dec 20 '21 at 13:22
1

Everything owned in the scope is droped ("cleaned") after the scope ends. In this case, if you want to manually drop it, you can, but need to make everything explicit to the compiler:

struct Obj {
    a: i32,
}

fn main() {
    let obj_a = Obj { a: 5 }; // get an owned object
    let mut a = &obj_a; // use a reference to the object
    a = &Obj { a: 6 }; // change to another object reference
    drop(obj_a); // drop the original OWNED object manually
}

Playground

What happens to the original Obj?

In your case you lose access to the owned version of the object, so it is just dropped at the end of the scope. But you can always have it in a variable that you can manually drop at any point you need.

if Rust has no GC, how to clean it by manual?

Use drop over owned data.

On the updated example:

why the 5 is not collected in the first place?

The compiler is smart enough to sometimes foresee that you are not really using anything there. Mi interpretation is that it is trying to optimise the code.

Check what happens if you manually drop the 5 obj.

use std::thread;
use std::time::Duration;


struct Obj {
    a: i32,
}

impl Drop for Obj {
    fn drop(&mut self) {
        println!("> Dropping {}", self.a);
    }
}

fn main() {
    let obj = Obj { a: 5 };
    let mut m = &obj;

    m = &Obj { a: 6 };
    drop(obj);
    m = &Obj { a: 7 };
    m = &Obj { a: 8 };

    let t = thread::spawn(|| {
        for i in 0..5 {
            println!("Counting {}", i);
            thread::sleep(Duration::from_secs_f32(1.0));
        }
    });
    t.join().unwrap();
}

Playground

Netwave
  • 40,134
  • 6
  • 50
  • 93
  • I have updated my question, and Implement a Drop Traint something interesting happened. – En Xie Dec 20 '21 at 12:53
  • @EnXie, I expanded the answer with your new example. But please do not keep updating the question, it is usually better to open a newly related question instead :) – Netwave Dec 20 '21 at 12:59
  • Got it. I will do it next time. many thx – En Xie Dec 20 '21 at 13:02
0

Rust ownership takes care of object lifetime. It is freed when out of the scope, unless moved meaning the responsibility to free it passed down to another scope.

Try adding Drop Traits to your object to see when it is freed.

Further reading,

tanmoy
  • 1,276
  • 1
  • 10
  • 28
  • 1
    I have tried the Drop Traits.. something interesting happened, I have updated my question. – En Xie Dec 20 '21 at 12:48