堆和栈,究其本质,是程序运行起来之后,供程序进程使用的虚拟内存中的地址空间。
一个可执行文件,运行起来之后就会成为操作系统中一个活动的进程。每一个进程都有自己独立的虚拟地址空间。
/// .Text段存放的是程序中的可执行代码
/// .Data段保存的是已经初始化了的全局变量和静态变量
/// .ROData(ReadOnlyData)段存放程序中的常量值,如字符串常量
/// .BSS段存放的是未初始化的全局变量和静态变量,程序执行前会先进行一遍初始化
const g_array: [i32; 5] = [10; 5];
const G_X: i32 = 100;
static G_VAR: i32 = 1000;
#[test]
fn test06_heap_or_stack() {
let s: &str = "test list";
//字符串字面量,位于ROData段
println!("&str: {:p}", s);//&str: 0x7ff77e4c6b88
println!("{:p}", &g_array);//data段:0x7ff6c5fc6bb8
println!("{:p}", &G_X);//data段:0x7ff6c5fc64f0
println!("{:p}", &G_VAR);//data段:0x7ff77e4c6200
println!("{}", "-".repeat(10));
}
// 位于堆
let b1 = Box::new(30);
let b2 = Box::new(30);
let b3 = Box::new(30);
println!("{:p}", b1);//堆:0x124f1a366d0
println!("{:p}", b2);//堆:0x124f1a367a0
println!("{:p}", b3);//堆:0x124f1a367c0
String::from
将字符串字面量从内存中的代码区(ROData段)复制一份到堆,并用栈上分配的变量指向堆内存。
// 栈上分配的变量s1指向堆内存
let mut s1: String = String::from("Hello");
// 可以通过std::mem::transmute将
// 从24字节的长度的3个uszie读出来
let pstr: [usize; 3] = unsafe { std::mem::transmute(s1) };
// 发现pstr[0]是一个堆内存地址
println!("ptr: 0x{:x}", pstr[0]);//ptr: 0x19f6c658750
// 从ROData区复制了一份字符串字面量放到堆上,
// 然后用栈上分配的s指向堆
let s: String = "Hello".to_owned();
println!("{:p}", &s);//0x116aeff1f8
let s: String = String::from("Hello");
println!("{:p}", &s);//0x116aeff260
let s: String = "Hello".into();
println!("{:p}", &s);//0x116aeff2c8
println!("{}", "-".repeat(10));
// 位于栈
let t = 100;
let nums1 = [1, 2, 3, 4, 5, 6];
let list: Vec<i32> = vec![20,30,40];
println!("{:p}", &t);//栈0xd2841ff33c
println!("{:p}", &nums1);//栈0xd2841ff340
println!("{:p}", &list);//栈0xd2841ff358