mirror of
https://github.com/bspeice/speice.io
synced 2024-12-22 08:38:09 -05:00
More tweaking
This commit is contained in:
parent
ab09489d32
commit
5efdcad0d2
@ -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<dyn Trait>`](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?
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user