在编写相对实时的代码时,通常避免主执行循环中的堆分配.因此,根据我的经验,您可以在初始化步骤中分配程序所需的所有内存,然后根据需要传递内存.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);
}
Run Code Online (Sandbox Code Playgroud)
而且我相信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);
}
Run Code Online (Sandbox Code Playgroud)
我想知道的是:Rust能够优化possibly_realtime,使得本地堆分配v只发生一次,并在后续调用中重用possibly_realtime吗?我猜不是,但也许有一些神奇使它成为可能.
截至目前,它尚未优化.要研究这一点,添加#[inline(never)]到您的函数,然后查看围栏上的LLVM IR是很有用的.这是一段摘录:
; 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
Run Code Online (Sandbox Code Playgroud)
也就是说,每次possibly_realtime调用时,都会通过分配内存je_mallocx.
重用缓冲区是泄露安全信息的好方法,我建议您尽可能避免使用它.我相信你已经熟悉这些问题,但我想确保未来的搜索者做出记录.
我也怀疑这个"优化"会被添加到Rust中,尤其是没有程序员明确选择加入.需要在某处可以存储指向已分配内存的指针,但实际上并不存在.这意味着它需要是一个全局或线程局部变量!Rust可以在没有线程的环境中运行,但是全局变量仍然会阻止对此方法的递归调用.总而言之,我认为经过缓冲区进入方法是很多更明确的了解会发生什么.
我还假设您的示例使用Vec具有固定大小的示例进行演示,但如果您在编译时确实知道大小,则固定大小的数组可能是更好的选择.
| 归档时间: |
|
| 查看次数: |
649 次 |
| 最近记录: |