3

The documentation states that if the type has a destructor, it won't be called: https://docs.rs/lazy_static/1.4.0/lazy_static/#semantics

So how am I supposed to free the memory?

gnevesdev
  • 47
  • 6
  • This is the behavior for all Rust `static` variables, not just `lazy_static`. See [Static Items](https://doc.rust-lang.org/reference/items/static-items.html) in the Rust Reference: *"Static items do not call drop at the end of the program"* – kmdreko Aug 20 '21 at 20:23

2 Answers2

8

So how am I supposed to free the memory?

That question isn't even wrong.

The entire point of lazy_static is that the object lives forever, that's what a static is, when would anything be freed? The note is there for non-memory Drop, to indicate that if e.g. you use lazy_static for a file or a temp they will not be flushed / deleted / … on program exit.

For memory stuff it'll be reclaimed by the system when the program exits, like all memory.

Masklinn
  • 34,759
  • 3
  • 38
  • 57
  • What if I want to store something that implements a destructor to free the memory? Like an Arc? And even worse, an Arc with a Mutex with a Box with something there. The Box will not free the heap stuff. – gnevesdev Aug 20 '21 at 19:51
  • 3
    @gnevesdev what functional difference would it make? The only conceivable time a static variable would be destroyed is at the end of the program, and at that point all the program's memory will be reclaimed by the OS anyway. – kmdreko Aug 20 '21 at 20:05
  • @kmdreko that does not mean it's not an issue. In other cases (like outside of an OS) the memory could be leaked. – gnevesdev Aug 20 '21 at 21:38
  • 2
    @gnevesdev again, what functional difference would it make? Especially in an OS-less bare-metal application, any memory that was in use has no effect on the system after your program ends. – kmdreko Aug 20 '21 at 22:19
4

So how am I supposed to free the memory?

Make your lazy_static an Option, and call take() to free the memory once you no longer need it. For example:

lazy_static! {
    static ref LARGE: Mutex<Option<String>> =
        Mutex::new(Some(iter::repeat('x').take(1_000_000).collect()));
}

fn main() {
    println!("using the string: {}", LARGE.lock().as_ref().unwrap().len());
    LARGE.lock().take();
    println!("string freed")
    assert!(LARGE.lock().is_none());
}

Playground

As others have pointed out, it is not necessary to do this kind of thing in most cases, as the point of most global variables is to last until the end of the program, at which case the memory will be reclaimed by the OS even if the destructor never runs.

The above can be useful if the global variable is associated with resources which you no longer need past a certain point in the program.

user4815162342
  • 141,790
  • 18
  • 296
  • 355