While learning “15.3. Running Code on Cleanup with the Drop Trait” of the Rust official book, I just wondered the memory layout of Rust program.
The default memory allocator provided by the operating system. This is based on
malloc
on Unix platforms andHeapAlloc
on Windows, plus related functions.
Just in case, here is the dirty code:
use std::ops::Deref;
struct MyBox<T>(T);
impl<T> MyBox<T> {
fn new(x: T) -> MyBox<T> {
MyBox(x)
}
}
impl<T> Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
fn hello(name: &str) {
let in_hello: usize = 61;
println!("&in_hello: {:p}", &in_hello);
println!("inside name: {:p}", name);
println!("inside &name: {:p}", &name);
}
fn main() {
// Stack variables
let stack_int_1: usize = 41;
let stack_int_2: usize = 42;
let stack_int_3: usize = 43;
let my_box = MyBox::new(String::from("Rust"));
// Heap variables
let string = String::from("bar");
//let string_slice: str = string[1..3]; // the size for values of type `str` cannot be known at compilation time
let heap_box_1 = Box::new(51);
let heap_box_2 = Box::new(String::from("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE"));
let heap_box_3 = Box::new(53);
let vec1: Vec<i64> = vec![0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9];
let vec2: Vec<u8> = vec![0,1,2,3,4,5,6,7,8,9];
let heap_box_4 = Box::new(54);
// Data segments
let static_str: &'static str = "foo";
let x: &[u8] = &[b'a', b'b', b'c'];
let stack_str: &str = std::str::from_utf8(x).unwrap();
let string_literal = "string literal";
let string_data: &str = "in data";
println!("\n==========================");
println!("Supposed to be in stack");
println!("==========================");
println!("&stack_int_1: {:p}", &stack_int_1);
println!("&stack_int_2: {:p}", &stack_int_2);
println!("&stack_int_3: {:p}", &stack_int_3);
println!("my_box: {:p}", &my_box);
println!("\nThe addresses are growing in defined order.");
println!("But, the order of variables inside a function stack frame is");
println!("irrelevant to growing direction of the stack.");
println!("\n==========================");
println!("Supposed to be in heap");
println!("==========================");
println!("&(*string) {:p}", &(*string));
println!("heap_box_1: {:p}", heap_box_1);
println!("heap_box_2: {:p}", heap_box_2);
println!("heap_box_3: {:p}", heap_box_3);
println!("&(*vec1): {:p}", &(*vec1));
println!("&(*vec2): {:p}", &(*vec2));
println!("heap_box_4: {:p}", heap_box_4);
println!("\nThe addresses are growing in defined order.");
println!("\n==========================");
println!("Supposed to be in data");
println!("==========================");
println!("static_str: &'static str {:p}", static_str);
println!("x: &[u8]: {:p}", x);
println!("stack_str: &str {:p}", stack_str);
println!("string_literal = '...': {:p}", string_literal);
println!("string_data: &str {:p}", string_data);
println!("\nThe addresses are growing in defined order.");
println!("\n\n");
let a = hello;
println!("function a: {:p}", &a);
a(&my_box);
}
And, this is the sample result:
==========================
Supposed to be in stack
==========================
&stack_int_1: 0x7fffcc413e90
&stack_int_2: 0x7fffcc413e98
&stack_int_3: 0x7fffcc413ea0
my_box: 0x7fffcc413ea8
The addresses are growing in defined order.
But, the order of variables inside a function stack frame is
irrelevant to growing direction of the stack.
==========================
Supposed to be in heap
==========================
&(*string) 0x5623955b8bc0
heap_box_1: 0x5623955b8be0
heap_box_2: 0x5623955b8c50
heap_box_3: 0x5623955b8c70
&(*vec1): 0x5623955b8c90
&(*vec2): 0x5623955b8d40
heap_box_4: 0x5623955b8d60
The addresses are growing in defined order.
==========================
Supposed to be in data
==========================
static_str: &'static str 0x56239496316e
x: &[u8]: 0x562394963171
stack_str: &str 0x562394963171
string_literal = '...': 0x56239496317f
string_data: &str 0x56239496318d
The addresses are growing in defined order.
function a: 0x7fffcc414760
&in_hello: 0x7fffcc413b80
inside name: 0x5623955b8ba0
inside &name: 0x7fffcc413b70
disclaimer: I ran the code on Ubuntu 20.04.
{:?}
points to a virtual memory address.
You can see stack is growing from high to low memory address (&in_hello
is lower than &stack_int_1
).
The default memory allocation
If you want to use system memory allocator explicitly, add the lines:
use std::alloc::System;
#[global_allocator]
static GLOBAL: System = System;
To be updated: &&str
is an address of stack