Skip to content

Commit 8200141

Browse files
committed
tutorial: Add a section on the memory model
1 parent 0e1a6cf commit 8200141

File tree

1 file changed

+76
-0
lines changed

1 file changed

+76
-0
lines changed

doc/tutorial.md

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -879,6 +879,82 @@ while (x > 10) { x -= 10; }
879879
assert x == 10;
880880
~~~~
881881
882+
# The Rust Memory Model
883+
884+
At this junction let's take a detour to explain the concepts involved
885+
in Rust's memory model. Rust has a very particular approach to
886+
memory management that plays a significant role in shaping the "feel"
887+
of the language. Understanding the memory landscape will illuminate
888+
several of Rust's unique features as we encounter them.
889+
890+
Rust has three competing goals that inform its view of memory:
891+
892+
* Memory safety - memory that is managed by and is accessible to
893+
the Rust language must be guaranteed to be valid. Under normal
894+
circumstances it is impossible for Rust to trigger a segmentation
895+
fault or leak memory
896+
* Performance - high-performance low-level code tends to employ
897+
a number of allocation strategies. low-performance high-level
898+
code often uses a single, GC-based, heap allocation strategy
899+
* Concurrency - Rust maintain memory safety guarantees even
900+
for code running in parallel
901+
902+
## How performance considerations influence the memory model
903+
904+
Many languages that ofter the kinds of memory safety guarentees that
905+
Rust does have a single allocation strategy: objects live on the heap,
906+
live for as long as they are needed, and are periodically garbage
907+
collected. This is very straightforword both conceptually and in
908+
implementation, but has very significant costs. Such languages tend to
909+
aggressively pursue ways to ameliorate allocation costs (think the
910+
Java virtual machine). Rust supports this strategy with _shared
911+
boxes_, memory allocated on the heap that may be referred to (shared)
912+
by multiple variables.
913+
914+
In comparison, languages like C++ offer a very precise control over
915+
where objects are allocated. In particular, it is common to put
916+
them directly on the stack, avoiding expensive heap allocation. In
917+
Rust this is possible as well, and the compiler will use a clever
918+
lifetime analysis to ensure that no variable can refer to stack
919+
objects after they are destroyed.
920+
921+
## How concurrency considerations influence the memory model
922+
923+
Memory safety in a concurrent environment tends to mean avoiding race
924+
conditions between two threads of execution accessing the same
925+
memory. Even high-level languages frequently avoid solving this
926+
problem, requiring programmers to correctly employ locking to unsure
927+
their program is free of races.
928+
929+
Rust solves this problem by starting from the position that memory
930+
simply cannot be shared between tasks. Experience in other languages
931+
has proven that isolating each tasks' heap from each other is
932+
a reliable strategy and one that is easy for programmers to reason
933+
about. Having isolated heaps additionally means that garbage collection
934+
must only be done per-heap. Rust never 'stops the world' to garbage
935+
collect memory.
936+
937+
If Rust tasks have completely isolated heaps then that seems to imply
938+
that any data transferred between them must be copied. While this
939+
is a fine and useful way to implement communication between tasks,
940+
it is also very inefficient for large data structures.
941+
942+
Because of this Rust also introduces a global "exchange heap". Objects
943+
allocated here have _ownership semantics_, meaning that there is only
944+
a single variable that refers to them. For this reason they are
945+
refered to as _unique boxes_. All tasks may allocate objects on this
946+
heap, then _move_ those allocations to other tasks, avoiding expensive
947+
copies.
948+
949+
## What to be aware of
950+
951+
Rust has three "realms" in which objects can be allocated: the stack,
952+
the local heap, and the exchange heap. These realms have corresponding
953+
pointer types: the borrowed pointer (`&T`), the shared pointer (`@T`),
954+
and the unique pointer (`~T`). These three sigils will appear
955+
repeatedly as we explore the language. Learning the appropriate role
956+
of each is key to using Rust effectively.
957+
882958
# Functions
883959
884960
Like all other static declarations, such as `type`, functions can be

0 commit comments

Comments
 (0)