TL; DR:从无拳击开始,然后轮廓。
堆栈分配VS盒装分配
这也许是更明确的:
虽然语义写作fn foo() -> Bar
意味着从被调用框架调用者帧移动Bar
,实际上,你更有可能以fn foo(__result: mut * Bar)
签名相当于是主叫其堆栈分配空间,并传递到结束一个指向被调用者的指针。
这可能并不总是足以避免复制,因为一些模式可能会阻止直接返还口写着:
fn defeat_copy_elision() -> WithDrop {
let one = side_effectful();
if side_effectful_too() {
one
} else {
side_effects_hurt()
}
}
这里,也没有神奇:
- 如果编译器使用
one
的返回槽,那么在分支评估为false
的情况下,它必须将one
移出然后将新的WithDrop
实例化到其中,最后销毁one
,
- 如果编译器在当前栈上实例化
one
,并且必须返回它,那么它必须执行一个副本。
如果类型不需要Drop
,那就没有问题了。
尽管有这些古怪的情况下,我建议坚持堆栈如果可能的话,除非分析显示它会是有益的箱子的地方。
联成员或盒装会员
这种情况要复杂得多:
结果,这是一个非常精细的平衡。对成员进行装箱或拆箱可能会提高代码库某些部分的性能,同时降低其他代码的性能。
肯定是有没有一个放之四海而皆准。
因此,再一次,我建议避免拳击,直到分析揭示了它会是有益的箱子的地方。
考虑在Linux上,任何内存分配针对其存在的过程中没有多余的内存可能需要一个系统调用,如果在操作系统没有备用内存可能触发OOM杀手杀死进程,在此时它的内存被抢救并可用。简单的malloc(1)
可能很容易要求毫秒。