Hands-On Concurrency with Rust
上QQ阅读APP看书,第一时间看更新

Allocating and deallocating memory

Deallocation happens in one of two ways, depending on whether the type is allocated on the stack or the heap. If it's on the stack, the type is deallocated when the stack frame itself ceases to exist. Each Rust stack frame comes into the world fully allocated but uninitialized and exits the world when its associated function exits. Heap allocated types are deallocated when the last valid binding moves out of scope, either through the natural flow of the program or by an explicit std::mem::drop being called by the programmer. The implementation of drop is as follows:

fn drop<T>(_x: T) { }

The value _x is moved into drop —meaning there are no other borrows of _x—and then immediately falls out of scope when drop exits. An explicit drop is not able to remove items from scope, however, so subtle interactions with structures where the Rust compiler is not able to prove non-overlapping aliases and the like will happen. The drop documentation discusses several cases and it is worth reviewing that material.

Any Rust type that can be deallocated—meaning it is not Copy—will implement the Drop trait, a trait whose sole function is drop(&mut self). Drop::drop cannot be called explicitly and is called when the type goes out of scope or is invocable by std::mem::drop, as discussed  previously.

So far in this chapter, we've discussed the layout of types in memory and allocation on the heap but without fully discussing how allocation itself works in the Rust memory model. The simplest way of forcing a heap allocation is with std::boxed::Box. In fact, the Rust documentation for Box—which is also just called box—describes it as the simplest form of heap allocation in Rust. That is, a Box<T> allocates enough space on the heap for a type T and acts as the owner of that allocation. When the box is dropped, the drop of T occurs. Here's the definition of Box<T> straight from the standard library, in the file src/liballoc/boxed.rs:

pub struct Box<T: ?Sized>(Unique<T>);