Search code examples
memory-managementrustmemory-layout

Why is the address of a second variable not right after the first variable?


I am aware that on a 64-bit system, a Vec will store an 8-byte pointer to the heap, 8 bytes for the capacity and 8 bytes for the length.

I assume that the address of a is right after the address of v, but when I checked the boundaries of the vector allocation on the stack, I found it always occupies 31 bytes of stack memory, 7 bytes more than it should. This goes the same for strings.

pub fn main() {
    let v = vec![1_u8];
    let a = 1_u8;

    let v_raw = &v as *const _;
    let a_raw = &a as *const _;

    println!("v addr = {:p}, dec = {}", v_raw, v_raw as usize);
    println!("a addr = {:p}, dec = {}", a_raw, a_raw as usize);
    println!("offset = {} bytes", a_raw as usize - v_raw as usize);

    // changing below 3 print will affect the mysterious 7 bytes
    //    println!("v_raw addr = {:p}", &v_raw);     // (1)
    //    println!("a_raw addr = {:p}", &a_raw);     // (2)
    println!("v as_ptr = {:p}", v.as_ptr()); // (3)

    // dereference through offset 24 to 30 -> 7 bytes
    let mut offset = 24_usize;
    loop {
        if offset == 31 {
            break;
        }

        // usize to *const usize(raw pointer)
        let mut addr = (v_raw as usize + offset) as *const usize;
        let deref_value = unsafe { *addr as u8 };

        println!(
            "offset = {}, addr = {:p}, value hex = {:x}, value = {}",
            offset, addr, deref_value, deref_value
        );

        offset += 1;
    }
}
v addr = 0x7fffbcf48b70, dec = 140736363531120
a addr = 0x7fffbcf48b8f, dec = 140736363531151
offset = 31 bytes
v as_ptr = 0x55d9c823ea40
offset = 24, addr = 0x7fffbcf48b88, value hex = 0, value = 0
offset = 25, addr = 0x7fffbcf48b89, value hex = 0, value = 0
offset = 26, addr = 0x7fffbcf48b8a, value hex = 0, value = 0
offset = 27, addr = 0x7fffbcf48b8b, value hex = 0, value = 0
offset = 28, addr = 0x7fffbcf48b8c, value hex = 0, value = 0
offset = 29, addr = 0x7fffbcf48b8d, value hex = 0, value = 0
offset = 30, addr = 0x7fffbcf48b8e, value hex = 0, value = 0

Sometimes these 7 extra addresses contains all 0 values, and sometimes not if I uncomment all the println! macros marked (1)(2)(3)

As I declared v and a in sequence, I was expecting that a is next to v on the stack, so why do I get these 7 bytes extra? Is this extra memory designed for something special?


Solution

  • I assume that the address of a is right after the address of v.

    Just because you wrote these variables in this order does not mean that Rust will store them consecutively on the stack. The Rust compiler is free to place things in memory wherever it sees fit, and you absolutely cannot rely on the ordering. The final ordering could be different depending on:

    • the version of the Rust compiler
    • if you are compiling for debug or release
    • the target operating system
    • the target CPU architecture
    • other code nearby in your application

    The actual size of the Vec can be shown to be 24:

    let v = vec![1_u8];
    println!("size = {}", std::mem::size_of_val(&v)); // size = 24
    

    See also: