<!doctype html><htmllang=endir=ltrclass="blog-wrapper blog-post-page plugin-blog plugin-id-default"data-has-hydrated=false><metacharset=UTF-8><metaname=generatorcontent="Docusaurus v3.6.1"><titledata-rh=true>Allocations in Rust: Dynamic memory | The Old Speice Guy</title><metadata-rh=truename=viewportcontent="width=device-width,initial-scale=1.0"><metadata-rh=truename=twitter:cardcontent=summary_large_image><metadata-rh=trueproperty=og:urlcontent=https://speice.io/2019/02/a-heaping-helping><metadata-rh=trueproperty=og:localecontent=en><metadata-rh=truename=docusaurus_localecontent=en><metadata-rh=truename=docusaurus_tagcontent=default><metadata-rh=truename=docsearch:languagecontent=en><metadata-rh=truename=docsearch:docusaurus_tagcontent=default><metadata-rh=trueproperty=og:titlecontent="Allocations in Rust: Dynamic memory | The Old Speice Guy"><metadata-rh=truename=descriptioncontent="Managing dynamic memory is hard. Some languages assume users will do it themselves (C, C++), and"><metadata-rh=trueproperty=og:descriptioncontent="Managing dynamic memory is hard. Some languages assume users will do it themselves (C, C++), and"><metadata-rh=trueproperty=og:typecontent=article><metadata-rh=trueproperty=article:published_timecontent=2019-02-07T12:00:00.000Z><linkdata-rh=truerel=iconhref=/img/favicon.ico><linkdata-rh=truerel=canonicalhref=https://speice.io/2019/02/a-heaping-helping><linkdata-rh=truerel=alternatehref=https://speice.io/2019/02/a-heaping-helpinghreflang=en><linkdata-rh=truerel=alternatehref=https://speice.io/2019/02/a-heaping-helpinghreflang=x-default><scriptdata-rh=truetype=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><linkrel=alternatetype=application/rss+xmlhref=/rss.xmltitle="The Old Speice Guy RSS Feed"><linkrel=alternatetype=application/atom+xmlhref=/atom.xmltitle="The Old Speice Guy Atom Feed"><linkrel=stylesheethref=/katex/katex.min.css><linkrel=stylesheethref=/assets/css/styles.16c3428d.css><scriptsrc=/assets/js/runtime~main.29a27dcf.jsdefer></script><scriptsrc=/assets/js/main.d461af80.jsdefer></script><bodyclass=navigation-with-keyboard><script>!function(){vart,e=function(){try{returnnewURLSearchParams(window.location.search).get("docusaurus-theme")}catch(t){}}()||function(){try{returnwindow.localStorage.getItem("theme")}catch(t){}}();t=null!==e?e:"light",document.documentElement.setAttribute("data-theme",t)}(),function(){try{for(var[t,e]ofnewURLSearchParams(window.location.search).entries())if(t.startsWith("docusaurus-data-")){vara=t.replace("docusaurus-data-","data-");document.documentElement.setAttribute(a,e)}}catch(t){}}()</script><divid=__docusaurus><divrole=regionaria-label="Skip to main content"><aclass=skipToContent_fXgnhref=#__docusaurus_skipToContent_fallback>Skip to main content</a></div><navaria-label=Mainclass="navbar navbar--fixed-top"><divclass=navbar__inner><divclass=navbar__items><buttonaria-label="Toggle navigation bar"aria-expanded=falseclass="navbar__toggle clean-btn"type=button><svgwidth=30height=30viewBox="0 0 30 30"aria-hidden=true><pathstroke=currentColorstroke-linecap=roundstroke-miterlimit=10stroke-width=2d="M4 7h22M4 15h22M4 23h22"/></svg></button><aclass=navbar__brandhref=/><divclass=navbar__logo><imgsrc=/img/logo.svgalt="Sierpinski Gasket"class="themedComponent_mlkZ themedComponent--light_NVdE"><imgsrc=/img/logo-dark.svgalt="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
<ahref=https://doc.rust-lang.org/book/ch04-00-understanding-ownership.htmltarget=_blankrel="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
<ahref=https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html#the-stack-and-the-heaptarget=_blankrel="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
<ahref=https://doc.rust-lang.org/book/ch04-01-what-is-ownership.htmltarget=_blankrel="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>
<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>
<h2class="anchor anchorWithStickyNavbar_LWe7"id=smart-pointers>Smart pointers<ahref=#smart-pointersclass=hash-linkaria-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 <ahref=https://en.wikipedia.org/wiki/Smart_pointertarget=_blankrel="noopener noreferrer">smart pointer</a> comes from C++, and while it's
closely linked to a general design pattern of
<ahref=https://en.cppreference.com/w/cpp/language/raiitarget=_blankrel="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
<p>Finally, there is one <ahref=https://www.merriam-webster.com/dictionary/gotchatarget=_blankrel="noopener noreferrer">"gotcha"</a>: <strong>cell types</strong>
(like <ahref=https://doc.rust-lang.org/stable/core/cell/struct.RefCell.htmltarget=_blankrel="noopener noreferrer"><code>RefCell</code></a>) look and behave
similarly, but <strong>don't involve heap allocation</strong>. The
<ahref=https://doc.rust-lang.org/stable/core/cell/index.htmltarget=_blankrel="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
<ahref=https://doc.rust-lang.org/stable/std/boxed/index.htmltarget=_blankrel="noopener noreferrer">gone out of scope</a> or a reference count
<ahref=https://doc.rust-lang.org/alloc/rc/index.htmltarget=_blankrel="noopener noreferrer">goes to zero</a>), the heap space is reclaimed. We can
prove these types use heap memory by looking at code:</p>
<h2class="anchor anchorWithStickyNavbar_LWe7"id=collections>Collections<ahref=#collectionsclass=hash-linkaria-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 <ahref=https://doc.rust-lang.org/std/vec/struct.Vec.html#method.reservetarget=_blankrel="noopener noreferrer">when needed</a>, and can
<ahref=https://doc.rust-lang.org/std/vec/struct.Vec.html#method.shrink_to_fittarget=_blankrel="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 <ahref=https://doc.rust-lang.org/stable/alloc/vec/struct.Vec.htmltarget=_blankrel="noopener noreferrer"><code>Vec</code></a>,
<ahref=https://doc.rust-lang.org/stable/std/collections/struct.HashMap.htmltarget=_blankrel="noopener noreferrer"><code>HashMap</code></a>, and
and <ahref=https://doc.rust-lang.org/std/string/struct.String.html#method.newtarget=_blankrel="noopener noreferrer"><code>String::new()</code></a>.</p>
<h2class="anchor anchorWithStickyNavbar_LWe7"id=heap-alternatives>Heap Alternatives<ahref=#heap-alternativesclass=hash-linkaria-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
(<ahref=https://doc.rust-lang.org/std/sync/struct.RwLock.htmltarget=_blankrel="noopener noreferrer"><code>RwLock</code></a> and
<ahref=https://doc.rust-lang.org/std/sync/struct.Mutex.htmltarget=_blankrel="noopener noreferrer"><code>Mutex</code></a>), stack-based alternatives are
provided in crates like <ahref=https://crates.io/crates/parking_lottarget=_blankrel="noopener noreferrer">parking_lot</a> and
<ahref=https://crates.io/crates/spintarget=_blankrel="noopener noreferrer">spin</a>. You can check out
<ahref=https://docs.rs/lock_api/0.1.5/lock_api/struct.Mutex.htmltarget=_blankrel="noopener noreferrer"><code>lock_api::Mutex</code></a>, and
<ahref=https://mvdnes.github.io/rust-docs/spin-rs/spin/struct.Once.htmltarget=_blankrel="noopener noreferrer"><code>spin::Once</code></a> if you're in need
of synchronization primitives.</p>
<p><ahref=https://crates.io/crates/thread-idtarget=_blankrel="noopener noreferrer">thread_id</a> may be necessary if you're implementing an allocator
because <ahref=https://doc.rust-lang.org/std/thread/struct.ThreadId.htmltarget=_blankrel="noopener noreferrer"><code>thread::current().id()</code></a> uses a
<h2class="anchor anchorWithStickyNavbar_LWe7"id=tracing-allocators>Tracing Allocators<ahref=#tracing-allocatorsclass=hash-linkaria-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,
<ahref="https://www.youtube.com/watch?v=2EWejmkKlxs&feature=youtu.be&t=263"target=_blankrel="noopener noreferrer">you don't care about it's performance</a>
You should never rely on your instincts when
<ahref="https://www.youtube.com/watch?v=NH1Tta7purM"target=_blankrel="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 <ahref=https://crates.io/crates/alloc_countertarget=_blankrel="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