为何我的Safe Rust代码会触发段错误或栈溢出?
Safe Rust代码触发段错误/栈溢出的原因
问题代码
use std::mem::size_of; const ROWS_PER_PAGE: usize = PAGE_SIZE / ROW_SIZE; const TABLE_MAX_ROWS: usize = TABLE_MAX_PAGES * ROWS_PER_PAGE; const ROW_SIZE: usize = ID_SIZE + USERNAME_SIZE + EMAIL_SIZE; const TABLE_MAX_PAGES: usize = 100; const PAGE_SIZE: usize = 4096; const ID_SIZE: usize = size_of::<u64>(); const USERNAME_SIZE: usize = 32; const EMAIL_SIZE: usize = 255; #[derive(Clone, Copy, Debug)] pub struct Page { buffer: [u8; PAGE_SIZE], } pub struct Table { pub pages: [Option<Page>; TABLE_MAX_ROWS], pub num_rows: usize, } impl Table { pub fn new() -> Self { Self { pages: [None; TABLE_MAX_ROWS], num_rows: 0, } } } fn main() { println!("{}", ROW_SIZE); let table = Table::new(); println!("{:p}", &table); }
运行报错
在MacBook Pro(aarch64-apple-darwin nightly工具链)上运行:
$ cargo r Finished dev [unoptimized + debuginfo] target(s) in 0.07s Running `target/debug/segfault` 295 [1] 68684 segmentation fault $ rustup show active-toolchain nightly-aarch64-apple-darwin (default)
在Rust Playground运行时直接提示Stack overflow。
问题原因
核心是栈上分配了超大型数组:
- 计算常量值:
ROW_SIZE = 8 + 32 + 255 = 295ROWS_PER_PAGE = 4096 / 295 = 13(整数除法取整)TABLE_MAX_ROWS = 100 * 13 = 1300
Table结构体中的pages是包含1300个Option<Page>的固定大小数组,每个Page本身占用4096字节内存,即使None状态的Option<Page>也会占用近似大小的内存(额外加1字节标记位)。- 整个
pages数组总内存占用约为1300 * 4097 ≈ 5.3MB,而程序栈空间通常仅几MB(macOS默认栈大小约8MB,debug模式下编译器额外开销会进一步压缩可用空间)。当main函数创建Table实例时,巨型数组直接分配在栈上,瞬间耗尽栈空间引发溢出——不同平台对栈溢出的表现不同,macOS触发段错误,Rust Playground直接检测并提示栈溢出。
解决方案
将大型数组从栈转移到堆上,比如用Vec<Option<Page>>替代固定大小数组:
// 修改Table结构体定义 pub struct Table { pub pages: Vec<Option<Page>>, pub num_rows: usize, } impl Table { pub fn new() -> Self { Self { // Vec会在堆上分配内存 pages: vec![None; TABLE_MAX_ROWS], num_rows: 0, } } }
这样数组内存会分配在堆上,栈上仅存储Vec的元数据(指针、长度、容量),不会再触发栈溢出问题。
内容的提问来源于stack exchange,提问作者Miss Yoimiya's puppy
相关产品推荐
相关产品推荐

