为什么同一 Rust 作用域中不相关的堆分配会损害性能?

mwl*_*lon 7 performance heap-memory rust

我有这种格式的代码:

fn f(n: usize) -> Result<Vec<usize>, String> {
  ...
  if some_runtime_condition {
    return Err("failure".to_string()); // LINE A
  }

  let mut v = Vec::with_capacity(n);
  while v.len() < n { // THE EXPENSIVE LOOP
    ... // complex logic building v
  }
  Ok(v)
}
Run Code Online (Sandbox Code Playgroud)

当我将 A 行更改为

return Err(format!("failure on {}", n)); // LINE A

调试(在发布模式下),我发现格式化错误字符串几乎花费了 0 时间,相反循环速度慢了 30-40%。据我了解,A 行的两个版本(就循环而言)之间唯一重要的区别是我使用格式字符串在当前范围内的堆上分配了其他数据。

我能够通过将代码更改为以下内容来解决性能问题并保留格式字符串:

#[inline(never)]
fn the_loop(n) -> Vec<usize> {
  let mut v = Vec::with_capacity(n);
  while v.len() < n { // THE EXPENSIVE LOOP
    ... // complex logic building v
  }
  Ok(v)
}

fn f(n: usize) -> Result<Vec<usize>, String> {
  ...
  if some_runtime_condition {
    return Err(format!("failure on {}", n)); // LINE A
  }

  Ok(the_loop(n))
}
Run Code Online (Sandbox Code Playgroud)

我没有想到一次堆分配会损害不同代码的性能,那么为什么会发生这种情况呢?有没有更好的方法告诉 Rust 编译器如何处理这个问题(除了#[inline(never)])?