How does Rust manage stack space while allocating arrays?

I test the code as following

fn test_stack_array() -> [u8; 512*1024] {
    let stack_top = 1;
    let array = [0; 512*1024];
    let stack_bottom = 1;
    println!("addr of (top, bottom) of stack is (0x{:x}, 0x{:x}), addr of (array[0], array[-1]) is (0x{:x}, 0x{:x})", 
         &stack_top as *const i32 as usize, &stack_bottom as *const i32 as usize, 
         &array[0] as *const u8 as usize, &array[512*1024-1] as *const u8 as usize);
   array
}

....
 let a = test_stack_array();
 println!("access array a[]:{}, addr of array out of function is : 0x{:x}", a[10], &a as *const u8 as usize);
.....

the result:

addr of (top, bottom) of stack is (0x19f610, 0x19f614), addr of (array[0], array[-1]) is (0x19f760, 0x21f75f)
access array a[]:0, addr of array out of function is : 0x19f760

returns the array allocated in function(at the stack space) , which means that space will not be freed. so does it mean the stack will exist many leaks and be managed like in heap? I think managing stack is more efficient than managing heap, is it correct?

Please help, thanks

Anything on the stack automatically disappears when the function exists.

The stack pointer moves down to make a space for the array on the stack, above it.

When the function returns the stack pointer is moved back up to where it was before the function call.

Your array is now unreachable below the stack pointer.

Calling another function will then be moving the stack pointer down and it will put it's local data above thus reusing you old array space.

If you are returning anything it will be copied from the functions stack area to the stack area of the caller.

4 Likes

Stack memory management is simpler and more efficient than heap memory management, yes, but that’s not the whole picture. When a Rust function returns, it moves (copies) the return value into the caller’s stack frame, which is not necessary if the object is stored on the heap. So there’s a tradeoff to be made here:

  • Heap: Expensive allocations and cheap moves (ownership transfers)
  • Stack: Cheap allocations and expensive moves

As values get larger, the move cost starts to dominate the allocation cost and the heap becomes preferable.

2 Likes

In this case, it looks like you've run into return value optimization. Rust can see that you create the local variable just to return it from the function, so it is created in the caller's stack, not in the callee's.

8 Likes

I'd just like to point out that while yes, "Heap memory being cheap to move and Stack memory being expensive to move", is the mental model you should probably use, once optimizations kick in it can become irrelevant. See

3 Likes

That does not sound quite right to me. When it comes down to actually copying bytes around it all boils down to memcpy() or some such that does not care where the memory it is copying is.

The trade off is the overheads of calling a memcpy, which gets bigger with data size, vs a cheap pointer move. Size is the key. Not stack or heap location.

Of course I would expect actually creating and destroying things on the stack to be a lot quicker than heap allocation/deallocation. So that plays into the equation as well.

Yes indeed.

3 Likes

Thanks @Cerber-Ursi and all. I almost forgot about this optimization....

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.