堆与栈
考虑到跟汇编语言的紧密联系,当我们谈论较底层语言的内存管理时,堆与栈(由于栈的管理是自动进行的,程序员更关心堆)是不可绕开的话题。在C语言中,堆管理依靠程序员手动释放;在Java和Python语言中,堆管理依靠垃圾回收器(GC);而在Rust语言中,堆管理依靠所有权与生命周期机制。
关于增长方向
在某些书上可能有明确表示,栈是向下增长的,堆是向上增长。这是不正确的。正确的说法是:栈的大小,增长方向等跟CPU体系结构,操作系统,编译器,甚至跟“上”“下”的定义都有关系,很难一概而论。
在Rust中,可以通过格式控制符来输出地址。
let n1 =1;
let n2 =2;
let n3 =3;
println!("n1,n2,n3的地址是:{:p},{:p},{:p}",&n1,&n2,&n3);
n1,n2,n3的地址是:0x9dfb0c,0x9dfb10,0x9dfb14
Box
在Rust中,值默认是由栈分配的。Rust标准库中实现了Box<T>,我们可以通过Box来把值分配到堆上。
C++用户们应该对智能指针不陌生:auto_ptr,shared_ptr, unique_ptr。Box也是一种智能指针,即:Box将数据存放在堆上,当指针在栈中的生命周期结束时,会自动解放指向的堆空间。
Box中实现了Pointer trait,可以用{:p}来输出地址。
let x:Box<i32> = Box::new(1);
println!("x的地址:{:p}",x);
println!("&x的地址:{:p}",&x);
x的地址:0xaa8240 &x地址:0x9dfb08
可以看出Box指向的数据是存放在堆区的,而Box本身在栈区。
Box的也可以用’*'解指针
let x = Box::new(1);
println!("x的地址:{:p}",x);
let y =*x;//如果x是未实现Copy trait的数据类型,会发生move
println!("y的地址:{:p}",&y);
x的地址:0xaf98e0 y的地址:0x9dfb54