You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust Serde嵌套含大数组结构体反序列化栈溢出解决方法

问题根因

触发栈溢出的核心原因是Foo类型的栈尺寸过大:长度30000的bool数组会占用近30KB栈空间。serde默认派生的反序列化逻辑会在栈上生成待构造值的临时副本,单独反序列化Foo时栈上的大数组副本少,不会超过栈阈值;但嵌套在Bar中反序列化时,多份大数组临时值叠加,很容易打满测试线程的默认栈空间(常规环境下测试线程栈大小仅512KB~2MB),最终触发栈溢出崩溃。

解决方案

优先选择堆分配存储大数组的根治方案,不需要调整运行时配置,在任何环境下都不会出现同类栈溢出问题:
将Foo中的大数组用Box包裹,把数组的实际内存挪到堆上,此时Foo类型本身仅占一个指针的大小(约8字节),从根源上消除栈上大内存占用。修改后的可运行代码如下:

use serde_big_array::BigArray;
use serde_derive::{Deserialize, Serialize};

pub const SIZE: usize = 30000;

#[derive(Clone, Debug, Serialize, Deserialize)]
struct Foo {
    #[serde(with = "BigArray")]
    pub vals: Box<[bool; SIZE]>,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
struct Bar {
    field0: Foo,
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn deserialization_attempt_test() {
        let foo = Foo {
            vals: Box::new([false; SIZE]),
        };
        let instance: Bar = Bar { field0: foo };
        let json = serde_json::to_string(&instance).unwrap();
        println!("PMD0");
        let s_back = serde_json::from_str::<Bar>(&json).unwrap();
        println!("PMD1");
    }
}

修改后访问数组元素的方式和原有逻辑完全一致,序列化生成的JSON格式也没有变化,不需要调整其他业务代码。

如果你暂时不想修改Foo的类型定义,可以临时通过增大线程最小栈空间的方式运行测试,但该方案治标不治本,程序在栈空间更小的环境运行时仍可能触发崩溃:

RUST_MIN_STACK=8388608 cargo t deserialization_attempt_test -- --nocapture

上述命令将测试线程最小栈设置为8MB,足够容纳多份大数组临时副本。

内容的提问来源于stack exchange,提问作者Thorkil Værge

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 20:27:16