bigywater.tech
Rust · 109

Rust 栈与堆分配

“局部变量在栈上,Box 和 Vec 在堆上”这句话怎么验证?栈到底多大?放不下会怎样?栈分配比堆分配快多少?这篇都用真实运行回答。

8176 KiB
这台机器主线程的栈上限(ulimit -s)
约 43468 层
每层约 150 字节栈帧的递归在主线程溢出前的深度
3.6×
256 字节缓冲区:堆分配比栈分配慢的倍数

变量在哪里

实测 · 本机执行输出
  编译:成功
  运行(退出码 0):
      局部变量 local       0x16f59e4d8
      数组 [u8; 64]      0x16f59e4e0
      Box<u64> 的数据     0x101245300
      Vec 的缓冲区         0x101245130
      String 的缓冲区      0x101245170
      字符串字面量           0x100899d78
      static           0x100899e08
      box 变量本身         0x16f59e520
      被调函数的局部          0x16f59e3b0
      main 函数代码        0x100860dc0

Box 见Box<T> 与堆分配。

栈的大小限制

实测 · 本机执行输出
  编译:成功
  ulimit -s(主线程栈上限,KiB):8176
  (深度用二分法测量:下面分别对主线程与子线程找到最大不溢出的递归层数)
  编译:成功
  主线程:每层约 150 字节栈帧,递归深度约 43468 层时还正常,再深就栈溢出(误差约 2%)
  子线程(默认栈):每层约 150 字节栈帧,递归深度约 10884 层时还正常,再深就栈溢出(误差约 2%)
  递归 400 万层:被信号 6 终止;stderr:['fatal runtime error: stack overflow, aborting']

线程栈大小见线程创建与 Join。

大数组

实测 · 本机执行输出
  编译:成功
  16 MiB 数组放栈上:被信号 6 终止;stderr 末行:['fatal runtime error: stack overflow, aborting']
  编译:成功
  运行(退出码 0):
    16 MiB 放在堆上:b[100] = 0,长度 16777216

分配成本

实测 · 本机执行输出
  编译:成功
  运行(退出码 0):
    栈上 [u8; 256]   每轮   3.39 ns
    堆上 vec![0u8; 256] 每轮  12.25 ns(分配 + 释放)

耗时是本机 release 微基准;栈上版本可能被优化器部分消除,只用于量级比较。

分步演示

栈与堆
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / rustc 1.98.1(brew)/ cargo 1.98.1;单个文件用 rustc 直接编译,需要依赖时用 cargo(经代理从 crates.io 下载);计时用 std::time::Instant,数字每次运行会有小幅抖动。macOS aarch64
    • 没有验证:Linux 上的栈布局与栈保护页、每层栈帧大小的精确值(只是估算)、glibc/其它分配器的成本、栈上数组被优化器完全消除的情形、堆的地址随机化(ASLR)每次运行的变化
    京ICP备2026067502号-1京公网安备11010502063487号