使用 Serde JSON 为什么“{c:[{}]}”在反序列化为 RawValue 结构时会导致堆分配?

With Serde JSON why does "{c:[{}]}" cause a heap allocation when deserializing into a RawValue struct?

我正在尝试了解堆分配在 Serde 中的工作原理 JSON。

为什么下面的代码会进行一次堆分配?我期望没有分配,因为 c 的值是使用 `#[serde(borrow)].

借来的 serde_json::value::RawValue
#[derive(Deserialize, Debug)]
struct MyStruct<'a> {
    #[serde(borrow)]
    c: &'a serde_json::value::RawValue,
}

fn main() {
    let msg = r#"{"c":[{}]}"#;

    // One unexpected allocation here.
    serde_json::from_str::<MyStruct>(msg).unwrap();

}

请注意,例如使用 {"c":[2, 3]} 而不是 {"c":[{}]} 将导致没有分配。

我怎样才能使反序列化为 MyStruct 时分配为零?

Rust playground link.

你无法避免分配。解析器需要在堆上分配一些内存,因为 JSON 对象和数组可以任意深度嵌套,并且它需要跟踪当前正在解析的值的类型。

modified your program 对解析过程中发生的第一次堆分配感到恐慌(因为我懒得调试,操场上没有调试器)。回溯显示堆分配的来源。关键帧是这个:

  14: serde_json::de::Deserializer<R>::ignore_value
             at ./.cargo/registry/src/github.com-1ecc6299db9ec823/serde_json-1.0.69/src/de.rs:1049:21

您可以确定您的 MyStruct 不会指向堆分配的内存,因为您的结构包含共享引用而不是拥有的值(并且输入是静态字符串)。为了 c 引用堆分配的内存,serde_json 必须 leak 它(但它并没有这样做;如果每次解析都可能泄漏内存,那就太糟糕了! ).

分配是 serde_json 的内部分配,将在返回前释放。有一个内部暂存区可能需要分配 (source)。

serde_json 的 README 也提到它依赖于 alloc 支持,所以分配并不意外:

As long as there is a memory allocator, it is possible to use serde_json without the rest of the Rust standard library.

如果您需要在没有分配的情况下工作,您可以尝试 serde-json-core,README 中也提到了这一点。