Placement new is a feature currently being discussed for the Rust programming
language. It gives programmer control of memory allocation and memory
placement, where current memory allocation implementations are hidden
behind compiler internals via the Box::new
interface. Controlling
memory allocation is useful in many different
applications, but a few that come to mind:
- Arena allocators: Pre-allocating big chunks of memory from the operating system up front, and arbitrating memory ownership directly in your application. This helps avoid context switches into the kernel for certain memory use-cases.
- Embedded allocators: Allocating chunks of memory from well-defined memory locations. Useful when you need memory to come from very specific hardware addresses.
This is Rust’s answer to C++ placement new, allowing one to control not only when and how memory is freed, but also where it is allocated and freed from (Thanks Holy_City for the clarification here!)
How heap allocation in Rust works now
Heap allocation is hidden behind the Box
type in Rust stable. When
you instantiate data within a Box
type, you’re placing the data onto
the heap, and the Box
type stores an internal pointer to that heap allocated
data.
If you dig around in the source of the Box type, you can see some hints at why ‘placement new’ might be useful.
Let’s see how Box::new
is implemented:
It looks like memory allocation, and lifting into the box type is hidden
behind this box
keyword. Searching
up on the box
keyword yields the Rust Documentation on unstable Box Syntax
and Patterns. This
unstable feature allows you to use the box
keyword to instantiate
allocated Box
es directly on the global heap.
What does the
Drop
implementation for
Box
look like?
I was expecting to see some unsafe dealloc calls here, but it looks like this work is being done somewhere in compiler internals.
How Placement New Fits
If you need to customize how heap allocation works, ideally, you’d be
able to hook into the box
keyword or use similar syntax (and avoid C++’esque
library solutions). This is exactly what Rust’s ‘placement new’
feature gives us. We need a way to use that fancy box
syntax (or
something similar), and
implement our own memory placement strategies.
The work on ‘placement new’ is broken down into a few different efforts that need to come together to make all of this work:
- A syntax extension that allows the programmer to specify where they’d like the memory placed. (RFC#1228),
- A Placer trait that would allow custom allocation / placement
implementations, that returns a
Place
type from thePlacer
s requiredmake_place
function. - Desugaring logic that transforms the syntax into straight
forward Rust code that calls the correct
Placer
s. - Implementations of existing implicit allocation / placement
strategies, including a
BoxPlace
for the defaultBox
heap allocation strategy.
Placement New Examples
There’s no clear consensus on how placement new syntax will work yet, but there are many options being discussed in RFC#1228. A few different options being discussed:
Overloaded ‘box’ syntax
We could overload the previously mentioned box
syntax above, and
allow it to take a place expression:
Left Arrow Syntax
Left arrow syntax,
follows the syntax PLACE_EXPR <- VALUE_EXPR
:
Placement ‘in’ syntax
Placement ‘in’ syntax uses the ‘in’ keyword to define the placement location.
Placer examples
The Placer
implementation for ExchangeHeapSingleton
(the
default box heap heap allocation method) implementation
that
was repealed from
Rust looked something like this:
And the corresponding Drop
implementation:
In this case, a Heap
type handles all the unsafe alloc / dealloc,
and the Place
returned from the Placer
is of type
IntermediateBox
.
Current feature status
It’s not clear yet when all these things will land, especially given the uncertainty around the placement syntax. Some of the initial work that was commited to Rust unstable (including syntax extensions and the Placer protocol traits) was subsequently removed in light of further design discussions needing to be had. Either way, I think placement new is an important feature for Rust. Adding explicit (but not required) control points to the internals of Rust will make it more appealing for certain use cases, including embedded and other applications that have special memory control requirements. I’m very much looking forward to this feature landing in Rust nightly.