mirror of
https://github.com/bspeice/speice.io
synced 2024-12-23 00:58:09 -05:00
83 lines
23 KiB
HTML
83 lines
23 KiB
HTML
|
<!doctype html><html lang=en dir=ltr class="blog-wrapper blog-post-page plugin-blog plugin-id-default" data-has-hydrated=false><meta charset=UTF-8><meta name=generator content="Docusaurus v3.6.0"><title data-rh=true>Allocations in Rust: Foreword | The Old Speice Guy</title><meta data-rh=true name=viewport content="width=device-width,initial-scale=1.0"><meta data-rh=true name=twitter:card content=summary_large_image><meta data-rh=true property=og:url content=https://speice.io/2019/02/understanding-allocations-in-rust><meta data-rh=true property=og:locale content=en><meta data-rh=true name=docusaurus_locale content=en><meta data-rh=true name=docusaurus_tag content=default><meta data-rh=true name=docsearch:language content=en><meta data-rh=true name=docsearch:docusaurus_tag content=default><meta data-rh=true property=og:title content="Allocations in Rust: Foreword | The Old Speice Guy"><meta data-rh=true name=description content="There's an alchemy of distilling complex technical topics into articles and videos that change the"><meta data-rh=true property=og:description content="There's an alchemy of distilling complex technical topics into articles and videos that change the"><meta data-rh=true property=og:type content=article><meta data-rh=true property=article:published_time content=2019-02-04T12:00:00.000Z><link data-rh=true rel=icon href=/img/favicon.ico><link data-rh=true rel=canonical href=https://speice.io/2019/02/understanding-allocations-in-rust><link data-rh=true rel=alternate href=https://speice.io/2019/02/understanding-allocations-in-rust hreflang=en><link data-rh=true rel=alternate href=https://speice.io/2019/02/understanding-allocations-in-rust hreflang=x-default><script data-rh=true type=application/ld+json>{"@context":"https://schema.org","@id":"https://speice.io/2019/02/understanding-allocations-in-rust","@type":"BlogPosting","author":{"@type":"Person","name":"Bradlee Speice"},"dateModified":"2024-11-10T02:05:00.000Z","datePublished":"2019-02-04T12:00:00.000Z","description":"There's an alchemy of distilling complex technical topics into articles and videos that change the","headline":"Allocations in Rust: Foreword","isPartOf":{"@id":"https://speice.io/","@type":"Blog","name":"Blog"},"keywords":[],"mainEntityOfPage":"https://speice.io/2019/02/understanding-allocations-in-rust","name":"Allocations in Rust: Foreword","url":"https://speice.io/2019/02/understanding-allocations-in-rust"}</script><link rel=alternate type=application/rss+xml href=/rss.xml title="The Old Speice Guy RSS Feed"><link rel=alternate type=application/atom+xml href=/atom.xml title="The Old Speice Guy Atom Feed"><link rel=stylesheet href=https://cdn.jsdelivr.net/npm/katex@0.13.24/dist/katex.min.css integrity=sha384-odtC+0UGzzFL/6PNoE8rX/SPcQDXBJ+uRepguP4QkPCm2LBxH3FA3y+fKSiJ+AmM crossorigin><link rel=stylesheet href=/assets/css/styles.ae6ff4a3.css><script src=/assets/js/runtime~main.751b419d.js defer></script><script src=/assets/js/main.62ce6156.js defer></script><body class=navigation-with-keyboard><script>!function(){var t,e=function(){try{return new URLSearchParams(window.location.search).get("docusaurus-theme")}catch(t){}}()||function(){try{return window.localStorage.getItem("theme")}catch(t){}}();t=null!==e?e:"light",document.documentElement.setAttribute("data-theme",t)}(),function(){try{for(var[t,e]of new URLSearchParams(window.location.search).entries())if(t.startsWith("docusaurus-data-")){var a=t.replace("docusaurus-data-","data-");document.documentElement.setAttribute(a,e)}}catch(t){}}()</script><div id=__docusaurus><div role=region aria-label="Skip to main content"><a class=skipToContent_fXgn href=#__docusaurus_skipToContent_fallback>Skip to main content</a></div><nav aria-label=Main class="navbar navbar--fixed-top"><div class=navbar__inner><div class=navbar__items><button aria-label="Toggle navigation bar" aria-expanded=false class="navbar__toggle clean-btn" type=button><svg width=30 height=30 viewBox="0 0 30 30" aria-hidden=true><path stroke=currentColor stroke-linecap=round stroke-miterlimit=10 stroke-width=2 d="M4 7h22M4 15h
|
||
|
way programmers see the tools they interact with on a regular basis. I knew what a linker was, but
|
||
|
there's a staggering amount of complexity in between
|
||
|
<a href="https://www.youtube.com/watch?v=dOfucXtyEsU" target=_blank rel="noopener noreferrer">the OS and <code>main()</code></a>. Rust programmers use the
|
||
|
<a href=https://doc.rust-lang.org/stable/std/boxed/struct.Box.html target=_blank rel="noopener noreferrer"><code>Box</code></a> type all the time, but there's a
|
||
|
rich history of the Rust language itself wrapped up in
|
||
|
<a href=https://manishearth.github.io/blog/2017/01/10/rust-tidbits-box-is-special/ target=_blank rel="noopener noreferrer">how special it is</a>.</p>
|
||
|
<p>In a similar vein, this series attempts 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 we're going to step into its world for a
|
||
|
while.</p>
|
||
|
<p>Let's learn a bit about memory in Rust.</p>
|
||
|
<hr>
|
||
|
<p>Rust's three defining features of
|
||
|
<a href=https://www.rust-lang.org/ target=_blank rel="noopener noreferrer">Performance, Reliability, and Productivity</a> are all driven to a great
|
||
|
degree by the how the Rust compiler understands memory usage. Unlike managed memory languages (Java,
|
||
|
Python), Rust
|
||
|
<a href=https://words.steveklabnik.com/borrow-checking-escape-analysis-and-the-generational-hypothesis target=_blank rel="noopener noreferrer">doesn't really</a>
|
||
|
garbage collect; instead, it uses an
|
||
|
<a href=https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html target=_blank rel="noopener noreferrer">ownership</a> system to reason about
|
||
|
how long objects will last in your program. In some cases, if the life of an object is fairly
|
||
|
transient, Rust can make use of a very fast region called the "stack." When that's not possible,
|
||
|
Rust uses
|
||
|
<a href=https://en.wikipedia.org/wiki/Memory_management#Dynamic_memory_allocation target=_blank rel="noopener noreferrer">dynamic (heap) memory</a>
|
||
|
and the ownership system to ensure you can't accidentally corrupt memory. It's not as fast, but it
|
||
|
is important to have available.</p>
|
||
|
<p>That said, there are specific situations in Rust where you'd never need to worry about the
|
||
|
stack/heap distinction! If you:</p>
|
||
|
<ol>
|
||
|
<li>Never use <code>unsafe</code></li>
|
||
|
<li>Never use <code>#![feature(alloc)]</code> or the <a href=https://doc.rust-lang.org/alloc/index.html target=_blank rel="noopener noreferrer"><code>alloc</code> crate</a></li>
|
||
|
</ol>
|
||
|
<p>...then it's not possible for you to use dynamic memory!</p>
|
||
|
<p>For some uses of Rust, typically embedded devices, these constraints are OK. They have very limited
|
||
|
memory, and the program binary size itself may significantly affect what's available! There's no
|
||
|
operating system able to manage this
|
||
|
<a href=https://en.wikipedia.org/wiki/Virtual_memory target=_blank rel="noopener noreferrer">"virtual memory"</a> thing, but that's not an issue
|
||
|
because there's only one running application. The
|
||
|
<a href=https://docs.rust-embedded.org/embedonomicon/preface.html target=_blank rel="noopener noreferrer">embedonomicon</a> is ever in mind, and
|
||
|
interacting with the "real world" through extra peripherals is accomplished by reading and writing
|
||
|
to <a href=https://bob.cs.sonoma.edu/IntroCompOrg-RPi/sec-gpio-mem.html target=_blank rel="noopener noreferrer">specific memory addresses</a>.</p>
|
||
|
<p>Most Rust programs find these requirements overly burdensome though. C++ developers would struggle
|
||
|
without access to <a href=https://en.cppreference.com/w/cpp/container/vector target=_blank rel="noopener noreferrer"><code>std::vector</code></a> (except those
|
||
|
hardcore no-STL people), and Rust developers would struggle without
|
||
|
<a href=https://doc.rust-lang.org/std/vec/struct.Vec.html target=_blank rel="noopener noreferrer"><code>std::vec</code></a>. But with the constraints above,
|
||
|
<code>std::vec</code> is actually a part of the
|
||
|
<a href=https://doc.rust-lang.org/alloc/vec/struct.Vec.html target=_blank rel="noopener noreferrer"><code>alloc</code> crate</a>, and thus off-limits. <code>Box</code>,
|
||
|
<code>Rc</code>, etc., are also unusable for the same reason.</p>
|
||
|
<p>Whether writing code for embedded devices or not, the important thing in both situations is how much
|
||
|
you know <em>before your application starts</em> about what its memory usage will look like. In embedded
|
||
|
devices, there's a small, fixed amount of memory to use. In a browser, you have no idea how large
|
||
|
<a href=https://www.google.com target=_blank rel="noopener noreferrer">google.com</a>'s home page is until you start trying to download it. The
|
||
|
compiler uses this knowledge (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 series is all about understanding how the compiler reasons about your program, with an
|
||
|
emphasis on the implications for performance.</p>
|
||
|
<p>Now let's address some conditions and caveats before going much further:</p>
|
||
|
<ul>
|
||
|
<li>We'll focus on "safe" Rust only; <code>unsafe</code> lets you use platform-specific allocation API's
|
||
|
(<a href=https://www.tutorialspoint.com/c_standard_library/c_function_malloc.htm target=_blank rel="noopener noreferrer"><code>malloc</code></a>) that we'll
|
||
|
ignore.</li>
|
||
|
<li>We'll assume a "debug" build of Rust code (what you get with <code>cargo run</code> and <code>cargo test</code>) and
|
||
|
address (pun intended) release mode at the end (<code>cargo run --release</code> and <code>cargo test --release</code>).</li>
|
||
|
<li>All content will be run using Rust 1.32, as that's the highest currently supported in the
|
||
|
<a href=https://godbolt.org/ target=_blank rel="noopener noreferrer">Compiler Exporer</a>. As such, we'll avoid upcoming innovations like
|
||
|
<a href=https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md target=_blank rel="noopener noreferrer">compile-time evaluation of <code>static</code></a>
|
||
|
that are available in nightly.</li>
|
||
|
<li>Because of the nature of the content, being able to read assembly is helpful. We'll keep it
|
||
|
simple, but I <a href=https://stackoverflow.com/a/4584131/1454178 target=_blank rel="noopener noreferrer">found</a> a
|
||
|
<a href=https://stackoverflow.com/a/26026278/1454178 target=_blank rel="noopener noreferrer">refresher</a> on the <code>push</code> and <code>pop</code>
|
||
|
<a href=http://www.cs.virginia.edu/~evans/cs216/guides/x86.html target=_blank rel="noopener noreferrer">instructions</a> was helpful while writing
|
||
|
this.</li>
|
||
|
<li>I've tried to be precise in saying only what I can prove using the tools (ASM, docs) that are
|
||
|
available, but if there's something said in error it will be corrected expeditiously. Please let
|
||
|
me know at <a href=mailto:bradlee@speice.io target=_blank rel="noopener noreferrer">bradlee@speice.io</a></li>
|
||
|
</ul>
|
||
|
<p>Finally, I'll do what I can to flag potential future changes but the Rust docs have a notice worth
|
||
|
repeating:</p>
|
||
|
<blockquote>
|
||
|
<p>Rust does not currently have a rigorously and formally defined memory model.</p>
|
||
|
<p>-- <a href=https://doc.rust-lang.org/std/ptr/fn.read_volatile.html target=_blank rel="noopener noreferrer">the docs</a></p>
|
||
|
</blockquote></div></article><nav class="pagination-nav docusaurus-mt-lg" aria-label="Blog post page navigation"><a class="pagination-nav__link pagination-nav__link--prev" href=/2018/12/allocation-safety><div class=pagination-nav__sublabel>Older post</div><div class=pagination-nav__label>QADAPT - debug_assert! for allocations</div></a><a class="pagination-nav__link pagination-nav__link--next" href=/2019/02/the-whole-world><div class=pagination-nav__sublabel>Newer post</div><div class=pagination-nav__label>Allocations in Rust: Global memory</div></a></nav></main></div></div></div><footer class=footer><div class="container container-fluid"><div class="footer__bottom text--center"><div class=footer__copyright>Copyright © 2024 Bradlee Speice</div></div></div></footer></div>
|