[Avg. reading time: 11 minutes]

Memory Layout

How many bytes does a type actually occupy?

The std::mem::size_of::() function helps you inspect the stack size of any type at compile time.

use std::mem;

fn main() {
    println!("i32    : {}", mem::size_of::<i32>());
    println!("u32    : {}", mem::size_of::<u32>());
    println!("f64    : {}", mem::size_of::<f64>());
    println!("char   : {}", mem::size_of::<char>());
    println!("&str   : {}", mem::size_of::<&str>());
    println!("String : {}", mem::size_of::<String>());
}
TypeSize (bytes)Why
i32432 bits = 4 bytes
u32432 bits unsigned
f64864-bit float
char4Unicode scalar value
&str16pointer (8) + length (8)
String24pointer (8) + length (8) + capacity (8)
TypeStack SizeHeap Usage
i324None
f648None
char4None
&str16No Ownership
String24Yes, for text
  • Primitive numeric types store values directly.
  • &str is a pointer containing a memory address and length.
  • String stores metadata on the stack but allocates its text on the heap.

String Literal points to location where Literal values are stored (Static Memory).

fn main(){
    let s = "Rachel";
    println!("{},{:p}", s, s.as_ptr())
}

Memory Alignment

CPUs generally do not read memory one byte at a time. Instead, they read in “words” (e.g., 8 bytes on a 64-bit system). If a multi-byte value is “misaligned”—meaning it straddles the boundary between two words—the CPU might have to perform two memory accesses instead of one, or in some architectures, it may trigger a hardware exception and crash.

use std::mem;

fn main() {
    let a: i32 = 42;
    let b: char = 'R';
    let c: String = String::from("Rachel");

    println!("Sizes and Alignments");
    println!("i32    -> size: {}, align: {}", mem::size_of::<i32>(), mem::align_of::<i32>());
    println!("char   -> size: {}, align: {}", mem::size_of::<char>(), mem::align_of::<char>());
    println!("String -> size: {}, align: {}", mem::size_of::<String>(), mem::align_of::<String>());

    println!("\nStack Addresses");
    println!("a (i32)    at {:p}", &a);
    println!("b (char)   at {:p}", &b);
    println!("c (String) at {:p}", &c);

    println!("\nHeap Address (String data)");
    println!("c text buffer at {:p}", c.as_ptr());
}

Padding & Memory Alignment

Padding: If you have a 1-byte variable followed by an 8-byte variable, the CPU can’t fit the big one into the remaining 7 bytes of its current “gulp” without splitting it. To avoid this, the computer leaves those 7 bytes empty. That empty space is padding.

Alignment: This is the rule that says data must be placed exactly where the CPU’s “gulp” starts. If you want an 8-byte integer, it needs to be perfectly lined up with the straw.

  • A value must start at a memory address that is a multiple of its alignment.
  • Alignment is determined by the type.

On a 64-bit system:

  • i32 Size = 4 bytes | Alignment = 4 bytes

  • u64, usize, String, pointers Size = 8 bytes (or more for String) | Alignment = 8 bytes

Example:

  • Bikes (1-byte) can park in any 1-foot slot.
  • Cars (4-bytes) must park in slots that are multiples of 4 (Slot 0, 4, 8…).
  • Buses (8-bytes) must park in slots that are multiples of 8 (Slot 0, 8, 16…).

Memory App Analyzer

Sometimes it takes time to start the app, please wait.

Memory App Analyzer

#memory #alignment #paddingVer 2.0.19

Last change: 2026-03-04