Search code examples
memoryrustmemory-model

Counterintuitive memory allocation


Created a small rust program to understand the memory allocation. Just wanted to understand if the data types use the memory area they are supposed to get allocated to.

fn main() {
    // stack
    let num: u8 = 89;
    // heap
    let boxed_num = Box::new(89);
    // stack
    let num2: u8 = 99;
    //heap
    let boxed_num2 = Box::new(99);
    // heap
    let s = String::from("hello");

    println!(
        "
        num:        {:p}
        boxed_num:  {:p}
        num2:       {:p}
        boxed_num2: {:p}
        string:     {:p}
        ",
        &num, &boxed_num, &num2, boxed_num2, &s
    );
}

I was expecting num and num2 to get allocated on stack

And boxed_num, boxed_num2 and s on heap

the program output was


        num:        0x7fff40d38def
        boxed_num:  0x7fff40d38df0
        num2:       0x7fff40d38dff
        boxed_num2: 0x55cf316c4af0
        string:     0x7fff40d38e08
       

But I was amazed when I checked the proc maps. It was

cat /proc/6182/maps
55cf316c4000-55cf316e5000 rw-p 00000000 00:00 0                          [heap]
7fff40d19000-7fff40d3b000 rw-p 00000000 00:00 0                          [stack]

How it could be possible? only boxed_num2 seems to be on heap and every other var goes to stack. Took multiple iterations. This pattern is consistent.

Why only boxed_num2 on heap?

Why boxed_num and s on stack?


Solution

  • Both boxed_num, boxed_num2 and s are objects that live on the stack and point to data on the heap.

    To get the heap part of Box/String, you need to call Box::as_ref() or String::as_bytes().

    The reason why boxed_num2 was shown on the heap was that you didn't add a & to it, causing an automatic dereference to its heap value. This is because {:p} expects a reference, and boxed_num2 can implicitely be converted into its heap value reference.

    Here you go:

    fn main() {
        // stack
        let num: u8 = 89;
        // heap
        let boxed_num = Box::new(89);
        // stack
        let num2: u8 = 99;
        //heap
        let boxed_num2 = Box::new(99);
        // heap
        let s = String::from("hello");
    
        println!(
            "
            num:        {:p}
            boxed_num:  {:p}
            num2:       {:p}
            boxed_num2: {:p}
            string:     {:p}
            ",
            &num,
            boxed_num.as_ref(),
            &num2,
            boxed_num2.as_ref(),
            s.as_bytes(),
        );
    }
    
            num:        0x7ffd1375d7cf
            boxed_num:  0x557006c71ad0
            num2:       0x7ffd1375d7df
            boxed_num2: 0x557006c71af0
            string:     0x557006c71b10