Rust能够优化本地堆分配吗?

时间:2015-04-06 19:32:47

标签: rust

在编写相对实时的代码时,通常避免在主执行循环中进行堆分配。因此,根据我的经验,您可以在初始化步骤中分配程序所需的所有内存,然后根据需要传递内存。 C中的玩具示例可能如下所示:

#include <stdlib.h>

#define LEN 100

void not_realtime() {
    int *v = malloc(LEN*sizeof(int));
    for (int i=0; i<LEN; i++) {
        v[i] = 1;
    }
    free(v);
}

void realtime(int *v, int len) {
    for (int i=0; i<len; i++) {
        v[i] = 1;
    }
}

int main(int argc, char **argv) {

    not_realtime();

    int *v = malloc(LEN*sizeof(int));
    realtime(v, LEN);
    free(v);
}

我相信Rust中的等价物:

fn possibly_realtime() {
    let mut v = vec![0; 100];
    for i in 0..v.len() {
        v[i] = 1;
    }
}

fn realtime(v: &mut Vec<i32>) {
    for i in 0..v.len() {
        v[i] = 1;
    }
}

fn main() {

    possibly_realtime();

    let mut v: Vec<i32> = vec![0; 100];
    realtime(&mut v);
}

我想知道的是:Rust能够优化possibly_realtime,以便v的本地堆分配只发生一次,并在后续调用possibly_realtime时重复使用吗?我猜不是,但也许有一些神奇使它成为可能。

2 个答案:

答案 0 :(得分:5)

截至目前,优化。要对此进行调查,向您的函数添加#[inline(never)]非常有用,然后查看LLVM IR on the playpen。这是一段摘录:

; Function Attrs: noinline uwtable
define internal fastcc void @_ZN17possibly_realtime20h1a3a159dd4b50685eaaE() unnamed_addr #0 {
entry-block:
  %0 = tail call i8* @je_mallocx(i64 400, i32 0), !noalias !0
  %1 = icmp eq i8* %0, null
  br i1 %1, label %then-block-255-.i.i, label %normal-return2.i

也就是说,每次调用possibly_realtime时,都会通过je_mallocx分配内存。

编辑

重用缓冲区是泄露安全信息的好方法,我建议您尽可能地避免使用。我相信你已经熟悉这些问题,但我想确保未来的搜索者做出记录。

我也怀疑这个“优化”会被添加到Rust中,特别是没有程序员明确选择加入。需要在某处可以存储指向已分配内存的指针,但实际上不是。这意味着它需要是一个全局或线程局部变量! Rust可以在没有线程的环境中运行,但是全局变量仍然会阻止对此方法的递归调用。总而言之,我认为将缓冲区传递给方法很多更明确地说明会发生什么。

我还假设您的示例使用具有固定大小的Vec用于演示目的,但如果您在编译时确实知道大小,则固定大小的数组可能是更好的选择。

答案 1 :(得分:0)

这是对 2015 年原始答案的更新。

截至 2021 年,rust 能够优化堆分配和内联 vtabke 方法调用:

https://play.rust-lang.org/?version=stable&mode=release&edition=2018&gist=78cf8db61cf6439aca345f2fdf3d0b56