Skip to content

Commit 929543d

Browse files
committed
Rewrite Memory Layout
1 parent 7f2024b commit 929543d

File tree

4 files changed

+81
-64
lines changed

4 files changed

+81
-64
lines changed

content/en/docs/c2.borrowing.md

Lines changed: 43 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -80,49 +80,58 @@ References are pointers that are either a thin pointer that points to a Sized ty
8080
use std::mem::size_of_val;
8181

8282
fn main() {
83-
let a = 3; // 💡 3 store on the stack
84-
let b: [i32; 3] = [1, 2, 3]; // 💡 [1, 2, 3] store inline on the stack
83+
let a = 3; // 3 stores on the stack
84+
let b = [1, 2, 3, 4, 5]; // [1, 2, 3, 4, 5] store inline on the stack
8585

86-
let c = &a; // 💡 c is a thin pointer (&i32) - [ptr]
87-
let d = &b; // 💡 d is also a thin pointer (&[i32; 3]) - [ptr]
88-
let e = &b[1..]; // 💡 [2, 3]; e is a fat pointer (&[i32]) - [ptr, len]
86+
let c = &a; // 💡 c is a thin pointer - [ptr] - points to `a`
87+
let d = &b; // 💡 d is a thin pointer - [ptr] - points to `b`
88+
let e = &b[1..3]; // 💡 e is a fat pointer - [ptr, len] - points to 2nd element of `b` and length is 2
8989

90-
println!("\nSize of actual data: a: {} bytes, b: {} bytes",
91-
size_of_val(&a), size_of_val(&b) // 4 and 12
90+
println!("Size of actual data: a: {} bytes, b: {} bytes",
91+
size_of_val(&a), size_of_val(&b) // 4, 20
9292
);
9393

9494
println!("Size of the references: c: {} bytes, d: {} bytes, e: {} bytes",
95-
size_of_val(&c), size_of_val(&d), size_of_val(&e) // 8 , 8, 16
95+
size_of_val(&c), size_of_val(&d), size_of_val(&e) // 8 , 8, 16 on 64-bit machines
9696
);
9797
}
98+
99+
// `d`: A reference to a fixed-size array, &[i32;5]. The compiler knows the length from the type.
100+
// `e`: A reference to a slice, &[i32]. Since the length is not part of the type,
101+
// it stores [address, length] at runtime, making it a fat pointer.
98102
```
99103

100-
> 💡 An array of Copy types stores its data inline (store elements contiguously) wherever it is declared. It lives on the stack as a local variable, in the binary if it is `static`, or on the heap if it is wrapped in a `Box` or `Vec`.
101-
>
102-
> ```rust
103-
> STACK
104-
> [ 1, 2, 3 ] // let b: [i32; 3] = [1, 2, 3];
105-
>
106-
> [ ptr ] // let d = &b; 💡 pointer points to 0th index element of the array + len(3) is baked into the Type
107-
> (Thin Ptr)
108-
>
109-
> [ ptr, len ] // let e = &b[1..]; 💡 pointer points to 1st index element of the array
110-
> (Fat Ptr)
111-
> ```
112-
113-
> 💡 An array of non-Copy types also stores its elements inline and contiguously wherever it is declared. However, each element acts as a "header" that contains a pointer to the actual data stored on the heap. Example: `[String; 3]`
114-
>
115-
> ```rust
116-
> STACK HEAP
117-
> [ String, String, String ] -> "A", "B", "C" // if `let b = [String::from("A"), String::from("B"), String::from("C")];`
118-
> 3x ( ptr, len, cap) (3 allocations)
119-
>
120-
> [ ptr ] // let d = &b; 💡 pointer points to 0th String Header
121-
> (Thin Ptr)
122-
>
123-
> [ ptr, len ] // let e = &b[1..]; 💡 pointer points to 1st String Header
124-
> (Fat Ptr)
125-
> ```
104+
| Variable Name | Type | Location | Size |
105+
|-----------------------------------------------------------------------|------------|----------|----------|
106+
| `a` | `i32` | Stack | 4 bytes |
107+
| `b` | `[i32;3]` | Stack | 12 bytes |
108+
| `c` (Stores the full memory address to `a`) | `&i32` | Stack | 8 bytes |
109+
| `d` (Stores the full memory address to `b`) | `&[i32;3]` | Stack | 8 bytes |
110+
| `e` (Stores the full memory address to 2nd element of `b` and length) | `&[i32]` | Stack | 16 bytes |
111+
112+
```rust
113+
use std::mem::size_of_val;
114+
115+
fn main() {
116+
// 💡 String stores [ptr, cap, len] on the stack, which points to "Hello" on the heap
117+
let a = String::from("Hello");
118+
119+
// 💡 Vec stores [ptr, cap, len] on the stack, which points to the array of &str on the heap
120+
let b = vec!["A", "B", "C", "D", "E"];
121+
122+
let c = &a; // 💡 c is a thin pointer - [ptr] - points to the String struct `a` on the stack
123+
let d = &b; // 💡 d is a thin pointer - [ptr] - points to the Vec struct `b` on the stack
124+
let e = &b[1..3]; // 💡 e is a fat pointer - [ptr, len] - points to the 2nd element in the heap buffer
125+
126+
println!("\nSize of stack metadata: a: {} bytes, b: {} bytes",
127+
size_of_val(&a), size_of_val(&b) // 24, 24
128+
);
129+
130+
println!("Size of the references: c: {} bytes, d: {} bytes, e: {} bytes",
131+
size_of_val(&c), size_of_val(&d), size_of_val(&e) // 8, 8, 16 on 64-bit machines
132+
);
133+
}
134+
```
126135

127136
## Shared Borrowing
128137

0 commit comments

Comments
 (0)