从我们的嵌入式系统代码中删除对malloc和calloc的所有调用之后,我惊讶地发现malloc仍然被链接。调用图指向了一个没有显式* alloc调用的函数,并且不调用任何可能分配的库函数,例如var result = (from inspArch in inspectionArchives
from inspAuth in inspArch.InspectionAuthority
group new { inspArch, inspAuth } by inspArch.CustomerId into g
select g).AsEnumerable()
.Select(g => new
{
Id = String.Join(",",g.Select(x => x.inspArch.Id),
clientId = x.Key,
authId = String.Join(",",g.Select(x => x.inspAuth.Id)
}).ToList();
我必须查看生成的程序集才能意识到它是由于包含VLA的内联函数。
我认为VLA必须是堆栈分配的。这个编译器坏了吗?
答案 0 :(得分:8)
不要求从堆栈中分配VLA(语言标准甚至没有提到堆栈或堆)。唯一的要求如下:
6.2.4对象的存储持续时间
...
7对于具有可变长度数组类型的此类对象,其生命周期延伸自 对象的声明,直到程序的执行离开了范围 声明。 35)如果以递归方式输入范围,则会创建该对象的新实例 每一次。对象的初始值是不确定的。 35)离开包含声明的最里面的块,或跳到该块中的一个点或一个 声明之前的嵌入块,留下了声明的范围。
鉴于此,从堆栈中分配是有意义的,但对于非常大的对象,这可能是不可能的,并且可以从堆或其他一些内存段中分配这样的对象。簿记取决于实施。
答案 1 :(得分:4)
不,它们不必进行堆栈分配。如果你希望它在堆栈中,我会使用<div ng-repeat="article in articles" ng-init="category=getCategory(article)"></div>
。
来源1:https://stackoverflow.com/a/2035292/283342
其次,VLA通常在堆栈上分配,但由于其可变大小,一般情况下,它在内存中的确切位置在编译时是未知的。因此,底层实现通常必须将其实现为指向内存块的指针。这引入了一些额外的内存开销(对于指针),由于上述原因,这又是完全无关紧要的。这也会带来轻微的性能开销,因为我们必须读取指针值才能找到实际的数组。这与访问malloc-ed数组时的开销相同(并且不会使用命名的编译时大小的数组)。
来源2:https://en.wikipedia.org/wiki/Variable-length_array
语言对VLA的支持可能隐藏的一个问题是底层内存分配:在堆和堆栈之间有明显区别的环境中,可能不清楚哪些(如果有的话)将存储VLA。