diff --git a/_drafts/understanding-allocations-in-rust.md b/_drafts/understanding-allocations-in-rust.md index a5568b8..8f48f0e 100644 --- a/_drafts/understanding-allocations-in-rust.md +++ b/_drafts/understanding-allocations-in-rust.md @@ -8,17 +8,17 @@ tags: [rust] There's an alchemy of distilling complex technical topics into articles and videos that change the way programmers see the tools they interact with on a regular basis. -I knew what a linker was, but there's a staggering complexity to get from -[from `main()` to an executable](https://www.youtube.com/watch?v=dOfucXtyEsU). +I knew what a linker was, but there's a staggering amount of complexity in between +[`main()` and your executable](https://www.youtube.com/watch?v=dOfucXtyEsU). Rust programmers use the [`Box`](https://doc.rust-lang.org/stable/std/boxed/struct.Box.html) type all the time, but there's a rich history of the Rust language itself wrapped up in [how special it is](https://manishearth.github.io/blog/2017/01/10/rust-tidbits-box-is-special/). -In a similar vein, I want you to look at code and understand memory; -the complex choreography of processor, operating system, and program that frees you +In a similar vein, I want you to look at code and understand how memory is used; +the complex choreography of operating system, compiler, and program that frees you to focus on functionality far-flung from frivolous book-keeping. The Rust compiler relieves -a great deal of the cognitive burden associated with memory management, but let's make time -to explore what's going on under the hood. +a great deal of the cognitive burden associated with memory management, but we're going +to step into its world for a while. Let's learn a bit about memory in Rust. @@ -30,16 +30,15 @@ section for easy citation in the future. To that end, a table of contents is pro to assist in easy navigation: - [Foreword](#foreword) -- [Non-Heap Memory Types](#non-heap-memory-types) -- [Piling On - Rust and the Heap](#piling-on-rust-and-the-heap) +- [Stacking Up: Non-Heap Memory Types](#non-heap-memory-types) +- [Piling On: Rust and the Heap](#piling-on-rust-and-the-heap) - [Compiler Optimizations Make Everything Complicated](#compiler-optimizations-make-everything-complicated) - Summary: When Does Rust Allocate? - [Appendix and Further Reading](#appendix-and-further-reading) # Foreword -There's a simple way to guarantee you never need to know the content -of this article: +There's a simple checklist to see if you can skip over reading this article. You must: 1. Only write `#![no_std]` crates 2. Never use `unsafe` @@ -47,35 +46,54 @@ of this article: For some uses of Rust, typically embedded devices, these constraints make sense. They're working with very limited memory, and the program binary size itself may -affect the memory available! There's no operating system able to manage the heap, -but that's not an issue because your program is likely the only one running. -The [embedonomicon] is ever in mind, and you just might interact with extra -peripherals by reading and writing to exact memory addresses. +significantly affect what's available! There's no operating system able to manage +this "virtual memory" junk, but that's not an issue because there's only one +running application. The [embedonomicon] is ever in mind, and interacting with the +"real world" through extra peripherals is accomplished by reading and writing to +exact memory addresses. Most Rust programs find these requirements overly burdensome though. C++ developers -would struggle without access to [`std::vector`](https://en.cppreference.com/w/cpp/container/vector), -and Rust developers would struggle without [`std::vec`](https://doc.rust-lang.org/std/vec/struct.Vec.html). -But in this scenario, `std::vec` is actually part of the -[`alloc` crate](https://doc.rust-lang.org/alloc/vec/struct.Vec.html), and thus off-limits. -Or how would you use trait objects? Rust's monomorphization still works, but there's no +would struggle without access to [`std::vector`](https://en.cppreference.com/w/cpp/container/vector) +(except those hardcore no-STL guys), and Rust developers would struggle without +[`std::vec`](https://doc.rust-lang.org/std/vec/struct.Vec.html). But in this scenario, +`std::vec` is actually part of the [`alloc` crate](https://doc.rust-lang.org/alloc/vec/struct.Vec.html), +and thus off-limits (because the `alloc` crate requires `#![feature(alloc)]`). +Or how would you use trait objects? There's no [`Box`](https://doc.rust-lang.org/alloc/boxed/struct.Box.html) available to use for dynamic dispatch. -Given a target audience of "basically every Rust developer," let's talk about -some of the details you don't normally have to worry about. This article will focus -on "safe" Rust only; `unsafe` mode allows you to make use of platform-specific -allocation APIs (think [libc] and [winapi] implementations of [malloc]) that -we'll ignore for the time being. We'll also assume a "debug" build of libraries -and applications (what you get with `cargo run` and `cargo test`) and address -"release" mode at the end (`cargo run --release` and `cargo test --release`). +Whether writing code for embedded devices or not, the important thing in both situations +is how much you know *before your application starts* about what your memory usage looks like. +In the embedded device example, there's a small, fixed amount of memory you can possibly use. +In a browser, however, you have no idea how large [google.com's home page] is until you start +trying to download it. The compiler uses this information (or lack thereof) to optimize +how memory is used; put simply, your code runs faster when the compiler can guarantee exactly +how much memory your program needs while it's running. This post is all about understanding +the optimization tricks the compiler uses, and how you can help the compiler and make +your programs more efficient. -Finally, a caveat: while the details are unlikely to change, the Rust docs +Now let's address some conditions and caveats before going much further. +This article will focus on "safe" Rust only; `unsafe` mode allows you +to make use of platform-specific allocation API's (think the [libc] and [winapi] +implementations of [malloc]) that we'll ignore. We'll also assume a "debug" +build of libraries and applications (what you get with `cargo run` and `cargo test`) +and address (hehe) "release" mode at the end (`cargo run --release` and `cargo test --release`). + +Finally, while the details are unlikely to change, the Rust docs include a warning worth repeating here: > Rust does not currently have a rigorously and formally defined memory model. > - the [Rust docs](https://doc.rust-lang.org/std/ptr/fn.read_volatile.html) -# Non-Heap Memory Types +# Stacking Up: Non-Heap Memory Types + +Languages like Java and Python do an amazing job of simplifying the memory model +needed for programmers. You can essentially treat + +Most of the reason this post was written is because I +Everyone's agreed that [compilers](https://www.youtube.com/watch?v=bSkpMdDe4g4) are +[smart](https://www.youtube.com/watch?v=nAbCKa0FzjQ), and Rust is no exception. + Example: Why doesn't `Vec::new()` go to the allocator?