mirror of
https://github.com/google/comprehensive-rust.git
synced 2025-03-27 08:15:40 +02:00
Tested with rust 2015, 2018, 2021 and 2024, on amd64 musl, amd64 glibc and aarch64 musl, all of them represent Strings with (ptr, capacity, len). This is an internal implementation detail, that shouldn't be exposed anyway, so it's no big deal, but in the speaker notes, we provide a debugging tool for demonstration purposes, so at least that should have a correct output.
2.4 KiB
2.4 KiB
minutes |
---|
5 |
Review of Program Memory
Programs allocate memory in two ways:
-
Stack: Continuous area of memory for local variables.
- Values have fixed sizes known at compile time.
- Extremely fast: just move a stack pointer.
- Easy to manage: follows function calls.
- Great memory locality.
-
Heap: Storage of values outside of function calls.
- Values have dynamic sizes determined at runtime.
- Slightly slower than the stack: some book-keeping needed.
- No guarantee of memory locality.
Example
Creating a String
puts fixed-sized metadata on the stack and dynamically sized
data, the actual string, on the heap:
fn main() {
let s1 = String::from("Hello");
}
Stack
.- - - - - - - - - - - - - -. Heap
: : .- - - - - - - - - - - - - - - -.
: s1 : : :
: +-----------+-------+ : : :
: | capacity | 5 | : : +----+----+----+----+----+ :
: | ptr | o-+---+-----+-->| H | e | l | l | o | :
: | len | 5 | : : +----+----+----+----+----+ :
: +-----------+-------+ : : :
: : : :
`- - - - - - - - - - - - - -' `- - - - - - - - - - - - - - - -'
-
Mention that a
String
is backed by aVec
, so it has a capacity and length and can grow if mutable via reallocation on the heap. -
If students ask about it, you can mention that the underlying memory is heap allocated using the System Allocator and custom allocators can be implemented using the Allocator API
More to Explore
We can inspect the memory layout with unsafe
Rust. However, you should point
out that this is rightfully unsafe!
fn main() {
let mut s1 = String::from("Hello");
s1.push(' ');
s1.push_str("world");
// DON'T DO THIS AT HOME! For educational purposes only.
// String provides no guarantees about its layout, so this could lead to
// undefined behavior.
unsafe {
let (capacity, ptr, len): (usize, usize, usize) = std::mem::transmute(s1);
println!("capacity = {capacity}, ptr = {ptr:#x}, len = {len}");
}
}