【发布时间】:2021-07-09 18:42:25
【问题描述】:
我一直在受限的嵌入式环境中使用 Rust(在 STM32F303 MCU 上),我注意到我的一些函数分配了出乎意料的大量堆栈空间。 在这种环境中,我没有分配器,需要在堆栈上分配大型、可变、静态的数据结构。 最终,我发现某些函数意外地在堆栈上分配空间,并导致我的内存受限堆栈溢出。
我希望了解以下mutate 函数需要在堆栈上分配多少内存。
我一直在这个网站上寻找这个问题的答案,但似乎没有人为这个更普遍的问题提供答案。
我知道对于下面的这个代码块,我可以查看 LLVM/程序集以查看分配的位置,但我试图了解如何预测何时为一般类问题进行堆栈分配 - 独立于编译器选项和优化器。
以下问题是一个玩具示例,它模仿了我在嵌入式 Rust 程序中使用(并且遇到问题)的模式。
问题:下面的mutate需要在栈上分配多少内存?
struct Parent {
data: Option<[u32; 1024]>,
}
impl Parent {
pub fn new() -> Self {
Parent { data: None }
}
// Ideally, this function should allocate negligible memory on the stack
pub fn mutate(&mut self) {
let arr = [0u32; 1024];
self.data = Some(arr);
for i in 0..self.data.unwrap().len() {
self.data.unwrap()[i] = i as u32;
}
}
}
fn main() {
let mut it = Parent::new();
it.mutate();
}
注意事项
- 其他帖子似乎表明这种行为取决于优化器。如果是这种情况,有没有办法可以重写上面的代码,以便代码的读者可以清楚地看到每个函数的堆栈分配大小?
- let 关键字(
mutate函数的第一行)对大数组是否在栈上分配有影响吗? - 我确信我可以使用
unsaferust 以确保该函数不需要进行任何分配/memcpys(就像我在 C 中所做的那样)。在不使用unsafe的情况下,有没有更好的方法来做到这一点?
在此先感谢您对此问题的任何帮助。
【问题讨论】:
-
如果您认为 Option 可以避免使用错误的数组大小。我不明白你的期望......这看起来像是 xy 问题的变化。
-
play.rust-lang.org/… 有什么问题?
-
我希望你意识到整个
for循环什么都不做,因为每个unwrap()都会复制整个数组。 -
感谢您的回复。我知道这里的选项将分配超过数组的大小,并且它不能用于节省空间。在我的程序中,Parent 结构可能处于多种状态,其中一种状态是数组尚未准备好使用,另一种状态是数组已由成员函数初始化为 Some,并准备好在计算。
-
改变数组的元素不需要复制任何东西(除了你改变它们的单个值)。您正在复制数组 而不是 对其进行变异。你基本上有this problem 除了
[u32; 1024]是Copy所以不存在所有权问题。如果你在不使用unwrap、it's initialization where the extraneous copy happens 的情况下改变数组的元素,这很难摆脱,但对于 LLVM 应该是相当容易处理的。
标签: memory rust embedded stack-overflow option-type