speice.io/2019/02/a-heaping-helping/index.html

122 lines
79 KiB
HTML
Raw Normal View History

<!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.1"><title data-rh=true>Allocations in Rust: Dynamic memory | 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/a-heaping-helping><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: Dynamic memory | The Old Speice Guy"><meta data-rh=true name=description content="Managing dynamic memory is hard. Some languages assume users will do it themselves (C, C++), and"><meta data-rh=true property=og:description content="Managing dynamic memory is hard. Some languages assume users will do it themselves (C, C++), and"><meta data-rh=true property=og:type content=article><meta data-rh=true property=article:published_time content=2019-02-07T12: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/a-heaping-helping><link data-rh=true rel=alternate href=https://speice.io/2019/02/a-heaping-helping hreflang=en><link data-rh=true rel=alternate href=https://speice.io/2019/02/a-heaping-helping hreflang=x-default><script data-rh=true type=application/ld+json>{"@context":"https://schema.org","@id":"https://speice.io/2019/02/a-heaping-helping","@type":"BlogPosting","author":{"@type":"Person","name":"Bradlee Speice"},"dateModified":"2024-11-10T02:05:00.000Z","datePublished":"2019-02-07T12:00:00.000Z","description":"Managing dynamic memory is hard. Some languages assume users will do it themselves (C, C++), and","headline":"Allocations in Rust: Dynamic memory","isPartOf":{"@id":"https://speice.io/","@type":"Blog","name":"Blog"},"keywords":[],"mainEntityOfPage":"https://speice.io/2019/02/a-heaping-helping","name":"Allocations in Rust: Dynamic memory","url":"https://speice.io/2019/02/a-heaping-helping"}</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=/katex/katex.min.css><link rel=stylesheet href=/assets/css/styles.16c3428d.css><script src=/assets/js/runtime~main.29a27dcf.js defer></script><script src=/assets/js/main.d461af80.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 15h22M4 23h22"/></svg></button><a class=navbar__brand href=/><div class=navbar__logo><img src=/img/logo.svg alt="Sierpinski Gasket" class="themedComponent_mlkZ themedComponent--light_NVdE"><img src=/img/logo-dark.svg alt="Sierpinski
some languages go to extreme lengths to protect users from themselves (Java, Python). In Rust, how
the language uses dynamic memory (also referred to as the <strong>heap</strong>) is a system called <em>ownership</em>.
And as the docs mention, ownership
<a href=https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html target=_blank rel="noopener noreferrer">is Rust's most unique feature</a>.</p>
<p>The heap is used in two situations; when the compiler is unable to predict either the <em>total size of
memory needed</em>, or <em>how long the memory is needed for</em>, it allocates space in the heap.</p>
<p>This happens
pretty frequently; if you want to download the Google home page, you won't know how large it is
until your program runs. And when you're finished with Google, we deallocate the memory so it can be
used to store other webpages. If you're interested in a slightly longer explanation of the heap,
check out
<a href=https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html#the-stack-and-the-heap target=_blank rel="noopener noreferrer">The Stack and the Heap</a>
in Rust's documentation.</p>
<p>We won't go into detail on how the heap is managed; the
<a href=https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html target=_blank rel="noopener noreferrer">ownership documentation</a> does a
phenomenal job explaining both the "why" and "how" of memory management. Instead, we're going to
focus on understanding "when" heap allocations occur in Rust.</p>
<p>To start off, take a guess for how many allocations happen in the program below:</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)"><div class=codeBlockContent_biex><pre tabindex=0 class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)"><code class=codeBlockLines_e6Vv><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token keyword" style="color:hsl(301, 63%, 40%)">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:hsl(221, 87%, 60%)">main</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">{</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">}</span><br></span></code></pre><div class=buttonGroup__atx><button type=button aria-label="Copy code to clipboard" title=Copy class=clean-btn><span class=copyButtonIcons_eSgA aria-hidden=true><svg viewBox="0 0 24 24" class=copyButtonIcon_y97N><path fill=currentColor d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"/></svg><svg viewBox="0 0 24 24" class=copyButtonSuccessIcon_LjdS><path fill=currentColor d=M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z /></svg></span></button></div></div></div>
<p>It's obviously a trick question; while no heap allocations occur as a result of that code, the setup
needed to call <code>main</code> does allocate on the heap. Here's a way to show it:</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)"><div class=codeBlockContent_biex><pre tabindex=0 class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)"><code class=codeBlockLines_e6Vv><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token attribute attr-name" style="color:hsl(35, 99%, 36%)">#![feature(integer_atomics)]</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token keyword" style="color:hsl(301, 63%, 40%)">use</span><span class="token plain"> </span><span class="token namespace">std</span><span class="token namespace punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token namespace">alloc</span><span class="token namespace punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">{</span><span class="token class-name" style="color:hsl(35, 99%, 36%)">GlobalAlloc</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">,</span><span class="token plain"> </span><span class="token class-name" style="color:hsl(35, 99%, 36%)">Layout</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">,</span><span class="token plain"> </span><span class="token class-name" style="color:hsl(35, 99%, 36%)">System</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">}</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">;</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token keyword" style="color:hsl(301, 63%, 40%)">use</span><span class="token plain"> </span><span class="token namespace">std</span><span class="token namespace punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token namespace">sync</span><span class="token namespace punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token namespace">atomic</span><span class="token namespace punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">{</span><span class="token class-name" style="color:hsl(35, 99%, 36%)">AtomicU64</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">,</span><span class="token plain"> </span><span class="token class-name" style="color:hsl(35, 99%, 36%)">Ordering</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">}</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">;</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain" style=display:inline-block></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token keyword" style="color:hsl(301, 63%, 40%)">static</span><span class="token plain"> </span><span class="token constant" style="color:hsl(35, 99%, 36%)">ALLOCATION_COUNT</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">:</span><span class="token plain"> </span><span class="token class-name" style="color:hsl(35, 99%, 36%)">AtomicU64</span><span class="token plain"> </span><span class="token operator" style="color:hsl(221, 87%, 60%)">=</span><span class="token plain"> </span><span class="token class-name" style="color:hsl(35, 99%, 36%)">AtomicU64</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token function" style="color:hsl(221, 87%, 60%)">new</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token number" style="color:hsl(35, 99%, 36%)">0</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">)</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">;</span><span class="token plain"></span><br>
<p>--
<a href="https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=fb5060025ba79fc0f906b65a4ef8eb8e" target=_blank rel="noopener noreferrer">Rust Playground</a></p>
<p>As of the time of writing, there are five allocations that happen before <code>main</code> is ever called.</p>
<p>But when we want to understand more practically where heap allocation happens, we'll follow this
guide:</p>
<ul>
<li>Smart pointers hold their contents in the heap</li>
<li>Collections are smart pointers for many objects at a time, and reallocate when they need to grow</li>
</ul>
<p>Finally, there are two "addendum" issues that are important to address when discussing Rust and the
heap:</p>
<ul>
<li>Non-heap alternatives to many standard library types are available.</li>
<li>Special allocators to track memory behavior should be used to benchmark code.</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id=smart-pointers>Smart pointers<a href=#smart-pointers class=hash-link aria-label="Direct link to Smart pointers" title="Direct link to Smart pointers"></a></h2>
<p>The first thing to note are the "smart pointer" types. When you have data that must outlive the
scope in which it is declared, or your data is of unknown or dynamic size, you'll make use of these
types.</p>
<p>The term <a href=https://en.wikipedia.org/wiki/Smart_pointer target=_blank rel="noopener noreferrer">smart pointer</a> comes from C++, and while it's
closely linked to a general design pattern of
<a href=https://en.cppreference.com/w/cpp/language/raii target=_blank rel="noopener noreferrer">"Resource Acquisition Is Initialization"</a>, we'll
use it here specifically to describe objects that are responsible for managing ownership of data
allocated on the heap. The smart pointers available in the <code>alloc</code> crate should look mostly
familiar:</p>
<ul>
<li><a href=https://doc.rust-lang.org/alloc/boxed/struct.Box.html target=_blank rel="noopener noreferrer"><code>Box</code></a></li>
<li><a href=https://doc.rust-lang.org/alloc/rc/struct.Rc.html target=_blank rel="noopener noreferrer"><code>Rc</code></a></li>
<li><a href=https://doc.rust-lang.org/alloc/sync/struct.Arc.html target=_blank rel="noopener noreferrer"><code>Arc</code></a></li>
<li><a href=https://doc.rust-lang.org/alloc/borrow/enum.Cow.html target=_blank rel="noopener noreferrer"><code>Cow</code></a></li>
</ul>
<p>The <a href=https://doc.rust-lang.org/std/ target=_blank rel="noopener noreferrer">standard library</a> also defines some smart pointers to manage
heap objects, though more than can be covered here. Some examples are:</p>
<ul>
<li><a href=https://doc.rust-lang.org/std/sync/struct.RwLock.html target=_blank rel="noopener noreferrer"><code>RwLock</code></a></li>
<li><a href=https://doc.rust-lang.org/std/sync/struct.Mutex.html target=_blank rel="noopener noreferrer"><code>Mutex</code></a></li>
</ul>
<p>Finally, there is one <a href=https://www.merriam-webster.com/dictionary/gotcha target=_blank rel="noopener noreferrer">"gotcha"</a>: <strong>cell types</strong>
(like <a href=https://doc.rust-lang.org/stable/core/cell/struct.RefCell.html target=_blank rel="noopener noreferrer"><code>RefCell</code></a>) look and behave
similarly, but <strong>don't involve heap allocation</strong>. The
<a href=https://doc.rust-lang.org/stable/core/cell/index.html target=_blank rel="noopener noreferrer"><code>core::cell</code> docs</a> have more information.</p>
<p>When a smart pointer is created, the data it is given is placed in heap memory and the location of
that data is recorded in the smart pointer. Once the smart pointer has determined it's safe to
deallocate that memory (when a <code>Box</code> has
<a href=https://doc.rust-lang.org/stable/std/boxed/index.html target=_blank rel="noopener noreferrer">gone out of scope</a> or a reference count
<a href=https://doc.rust-lang.org/alloc/rc/index.html target=_blank rel="noopener noreferrer">goes to zero</a>), the heap space is reclaimed. We can
prove these types use heap memory by looking at code:</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)"><div class=codeBlockContent_biex><pre tabindex=0 class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)"><code class=codeBlockLines_e6Vv><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token keyword" style="color:hsl(301, 63%, 40%)">use</span><span class="token plain"> </span><span class="token namespace">std</span><span class="token namespace punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token namespace">rc</span><span class="token namespace punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token class-name" style="color:hsl(35, 99%, 36%)">Rc</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">;</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token keyword" style="color:hsl(301, 63%, 40%)">use</span><span class="token plain"> </span><span class="token namespace">std</span><span class="token namespace punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token namespace">sync</span><span class="token namespace punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token class-name" style="color:hsl(35, 99%, 36%)">Arc</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">;</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token keyword" style="color:hsl(301, 63%, 40%)">use</span><span class="token plain"> </span><span class="token namespace">std</span><span class="token namespace punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token namespace">borrow</span><span class="token namespace punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token class-name" style="color:hsl(35, 99%, 36%)">Cow</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">;</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain" style=display:inline-block></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token keyword" style="color:hsl(301, 63%, 40%)">pub</span><span class="token plain"> </span><span class="token keyword" style="color:hsl(301, 63%, 40%)">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:hsl(221, 87%, 60%)">my_box</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">{</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token comment" style="color:hsl(230, 4%, 64%)">// Drop at assembly line 1640</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token class-name" style="color:hsl(35, 99%, 36%)">Box</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token function" style="color:hsl(221, 87%, 60%)">new</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token number" style="color:hsl(35, 99%, 36%)">0</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">)</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">;</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">}</span><span class="token pla
<p>-- <a href=https://godbolt.org/z/4AMQug target=_blank rel="noopener noreferrer">Compiler Explorer</a></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id=collections>Collections<a href=#collections class=hash-link aria-label="Direct link to Collections" title="Direct link to Collections"></a></h2>
<p>Collection types use heap memory because their contents have dynamic size; they will request more
memory <a href=https://doc.rust-lang.org/std/vec/struct.Vec.html#method.reserve target=_blank rel="noopener noreferrer">when needed</a>, and can
<a href=https://doc.rust-lang.org/std/vec/struct.Vec.html#method.shrink_to_fit target=_blank rel="noopener noreferrer">release memory</a> when it's
no longer necessary. This dynamic property forces Rust to heap allocate everything they contain. In
a way, <strong>collections are smart pointers for many objects at a time</strong>. Common types that fall under
this umbrella are <a href=https://doc.rust-lang.org/stable/alloc/vec/struct.Vec.html target=_blank rel="noopener noreferrer"><code>Vec</code></a>,
<a href=https://doc.rust-lang.org/stable/std/collections/struct.HashMap.html target=_blank rel="noopener noreferrer"><code>HashMap</code></a>, and
<a href=https://doc.rust-lang.org/stable/alloc/string/struct.String.html target=_blank rel="noopener noreferrer"><code>String</code></a> (not
<a href=https://doc.rust-lang.org/std/primitive.str.html target=_blank rel="noopener noreferrer"><code>str</code></a>).</p>
<p>While collections store the objects they own in heap memory, <em>creating new collections will not
allocate on the heap</em>. This is a bit weird; if we call <code>Vec::new()</code>, the assembly shows a
corresponding call to <code>real_drop_in_place</code>:</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)"><div class=codeBlockContent_biex><pre tabindex=0 class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)"><code class=codeBlockLines_e6Vv><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token keyword" style="color:hsl(301, 63%, 40%)">pub</span><span class="token plain"> </span><span class="token keyword" style="color:hsl(301, 63%, 40%)">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:hsl(221, 87%, 60%)">my_vec</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">{</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token comment" style="color:hsl(230, 4%, 64%)">// Drop in place at line 481</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token class-name" style="color:hsl(35, 99%, 36%)">Vec</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token operator" style="color:hsl(221, 87%, 60%)">&lt;</span><span class="token keyword" style="color:hsl(301, 63%, 40%)">u8</span><span class="token operator" style="color:hsl(221, 87%, 60%)">></span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token function" style="color:hsl(221, 87%, 60%)">new</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">)</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">;</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">}</span><br></span></code></pre><div class=buttonGroup__atx><button type=button aria-label="Copy code to clipboard" title=Copy class=clean-btn><span class=copyButtonIcons_eSgA aria-hidden=true><svg viewBox="0 0 24 24" class=copyButtonIcon_y97N><path fill=currentColor d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"/></svg><svg viewBox="0 0 24 24" class=copyButtonSuccessIcon_LjdS><path fill=currentColor d=M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z /></svg></span></button></div></div></div>
<p>-- <a href=https://godbolt.org/z/1WkNtC target=_blank rel="noopener noreferrer">Compiler Explorer</a></p>
<p>But because the vector has no elements to manage, no calls to the allocator will ever be dispatched:</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)"><div class=codeBlockContent_biex><pre tabindex=0 class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)"><code class=codeBlockLines_e6Vv><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token keyword" style="color:hsl(301, 63%, 40%)">use</span><span class="token plain"> </span><span class="token namespace">std</span><span class="token namespace punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token namespace">alloc</span><span class="token namespace punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">{</span><span class="token class-name" style="color:hsl(35, 99%, 36%)">GlobalAlloc</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">,</span><span class="token plain"> </span><span class="token class-name" style="color:hsl(35, 99%, 36%)">Layout</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">,</span><span class="token plain"> </span><span class="token class-name" style="color:hsl(35, 99%, 36%)">System</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">}</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">;</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token keyword" style="color:hsl(301, 63%, 40%)">use</span><span class="token plain"> </span><span class="token namespace">std</span><span class="token namespace punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token namespace">sync</span><span class="token namespace punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token namespace">atomic</span><span class="token namespace punctuation" style="color:hsl(119, 34%, 47%)">::</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">{</span><span class="token class-name" style="color:hsl(35, 99%, 36%)">AtomicBool</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">,</span><span class="token plain"> </span><span class="token class-name" style="color:hsl(35, 99%, 36%)">Ordering</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">}</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">;</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain" style=display:inline-block></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token keyword" style="color:hsl(301, 63%, 40%)">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:hsl(221, 87%, 60%)">main</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">{</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token comment" style="color:hsl(230, 4%, 64%)">// Turn on panicking if we allocate on the heap</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token constant" style="color:hsl(35, 99%, 36%)">DO_PANIC</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">.</span><span class="token function" style="color:hsl(221, 87%, 60%)">store</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">(</span><span class="token boolean" style="color:hsl(35, 99%, 36%)">true</span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">,</span><span class="token plain">
<p>--
<a href="https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=831a297d176d015b1f9ace01ae416cc6" target=_blank rel="noopener noreferrer">Rust Playground</a></p>
<p>Other standard library types follow the same behavior; make sure to check out
<a href=https://doc.rust-lang.org/std/collections/hash_map/struct.HashMap.html#method.new target=_blank rel="noopener noreferrer"><code>HashMap::new()</code></a>,
and <a href=https://doc.rust-lang.org/std/string/struct.String.html#method.new target=_blank rel="noopener noreferrer"><code>String::new()</code></a>.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id=heap-alternatives>Heap Alternatives<a href=#heap-alternatives class=hash-link aria-label="Direct link to Heap Alternatives" title="Direct link to Heap Alternatives"></a></h2>
<p>While it is a bit strange to speak of the stack after spending time with the heap, it's worth
pointing out that some heap-allocated objects in Rust have stack-based counterparts provided by
other crates. If you have need of the functionality, but want to avoid allocating, there are
typically alternatives available.</p>
<p>When it comes to some standard library smart pointers
(<a href=https://doc.rust-lang.org/std/sync/struct.RwLock.html target=_blank rel="noopener noreferrer"><code>RwLock</code></a> and
<a href=https://doc.rust-lang.org/std/sync/struct.Mutex.html target=_blank rel="noopener noreferrer"><code>Mutex</code></a>), stack-based alternatives are
provided in crates like <a href=https://crates.io/crates/parking_lot target=_blank rel="noopener noreferrer">parking_lot</a> and
<a href=https://crates.io/crates/spin target=_blank rel="noopener noreferrer">spin</a>. You can check out
<a href=https://docs.rs/lock_api/0.1.5/lock_api/struct.RwLock.html target=_blank rel="noopener noreferrer"><code>lock_api::RwLock</code></a>,
<a href=https://docs.rs/lock_api/0.1.5/lock_api/struct.Mutex.html target=_blank rel="noopener noreferrer"><code>lock_api::Mutex</code></a>, and
<a href=https://mvdnes.github.io/rust-docs/spin-rs/spin/struct.Once.html target=_blank rel="noopener noreferrer"><code>spin::Once</code></a> if you're in need
of synchronization primitives.</p>
<p><a href=https://crates.io/crates/thread-id target=_blank rel="noopener noreferrer">thread_id</a> may be necessary if you're implementing an allocator
because <a href=https://doc.rust-lang.org/std/thread/struct.ThreadId.html target=_blank rel="noopener noreferrer"><code>thread::current().id()</code></a> uses a
<a href=https://doc.rust-lang.org/stable/src/std/sys_common/thread_info.rs.html#17-36 target=_blank rel="noopener noreferrer"><code>thread_local!</code> structure</a>
that needs heap allocation.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id=tracing-allocators>Tracing Allocators<a href=#tracing-allocators class=hash-link aria-label="Direct link to Tracing Allocators" title="Direct link to Tracing Allocators"></a></h2>
<p>When writing performance-sensitive code, there's no alternative to measuring your code. If you
didn't write a benchmark,
<a href="https://www.youtube.com/watch?v=2EWejmkKlxs&feature=youtu.be&t=263" target=_blank rel="noopener noreferrer">you don't care about it's performance</a>
You should never rely on your instincts when
<a href="https://www.youtube.com/watch?v=NH1Tta7purM" target=_blank rel="noopener noreferrer">a microsecond is an eternity</a>.</p>
<p>Similarly, there's great work going on in Rust with allocators that keep track of what they're doing
(like <a href=https://crates.io/crates/alloc_counter target=_blank rel="noopener noreferrer"><code>alloc_counter</code></a>). When it comes to tracking heap
behavior, it's easy to make mistakes; please write tests and make sure you have tools to guard
against future issues.</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=/2019/02/stacking-up><div class=pagination-nav__sublabel>Older post</div><div class=pagination-nav__label>Allocations in Rust: Fixed memory</div></a><a class="pagination-nav__link pagination-nav__link--next" href=/2019/02/08/compiler-optimizations><div class=pagination-nav__sublabel>Newer post</div><div class=pagination-nav__label>Allocations in Rust: Compiler optimizations</div></a></nav></main><div class="col col--2"><div class="tableOfContents_bqdL thin-scrollbar"><ul class="table-of-contents table-of-contents__left-border"><li><a href=#smart-pointers class="table-of-contents__link toc-highlight">Smart pointers</a><li><a href=#collections class="table-of-contents__link toc-highlight">Collections</a><li><a href=#heap-alternatives class="table-of-contents__link toc-highlight">Heap Alternatives</a><li><a href=#tracing-allocators class="table-of-contents__link toc-highlight">Tracing Allocators</a></ul></div></div></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>