数组分配的alloca与simple []数组声明的有利性

时间:2014-02-05 15:42:39

标签: objective-c c macos memory-management

阅读一些Apple代码,我偶然发现了以下C块

alloca(sizeof(CMTimeRange) * 3)

与分配堆栈内存通过

相同

CMTimeRange *p = CMTimeRange[3]

对性能有任何影响吗?是否需要释放记忆?

3 个答案:

答案 0 :(得分:0)

假设Joachim指出你的意思是CMTimeRange someVariableName[3] ......

两者都会在堆栈上分配内存。

我猜alloca()必须在你的函数序言之后添加额外的代码来进行分配...函数序言是编译器自动生成的代码,用于在堆栈上创建空间。结果是你的函数在编译后可能会略大一些,但不是很多......一些额外的指令来修改堆栈指针和可能的堆栈帧。我想编译器可以优化调用,如果它不在条件分支中,或者甚至将它提升到条件分支之外呢?

我在没有优化的情况下对我的MQX编译器进行了实验......它不是客观的,只是C,也是一个不同的平台,但希望这是一个足够好的近似并且确实显示了发出的代码的差异。我在堆栈上使用了两个带有大数组的简单函数,以确保必须使用堆栈空间(变量不能仅存在于寄存器中)。

显然不建议将大型数组放在堆栈上......这仅用于演示目的。

unsigned int TEST1(unsigned int stuff)
{
    unsigned int a1[100]; // Make sure it must go on stack
    unsigned int a2[100]; // Make sure it must go on stack
    a1[0] = 0xdead;
    a2[0] = stuff + 10;
    return a2[0];
}

unsigned int TEST2(unsigned int stuff)
{
    unsigned int a1[100]; // Make sure it must go on stack
    unsigned int *a2 = alloca(sizeof(unsigned int)*100);
    a1[0] = 0xdead;
    a2[0] = stuff + 10;
    return a2[0];
}

生成了以下汇编程序:

<强> TEST1: 数组a1a2都放在函数序言中的堆栈中......

   0: 1cfcb6c8                 push %fp
   4: 230a3700                 mov  %fp,%sp
   8: 24993901                 sub3 %sp,%sp,100    # Both arrays put on stack
   c: 7108                     mov_s    %r1,%r0
   e: 1b38bf98 0000dead        st   0xdead,[%fp,0xffff_fce0]        ; 0xdead
  16: e00a                     add_s    %r0,%r0,10
  18: 1b9cb018                 st   %r0,[%fp,0xffff_fe70]
  1c: 240a36c0                 mov  %sp,%fp
  20: 1404341b                 pop  %fp
  24: 7ee0                     j_s  [%blink]

<强> TEST2: 只有数组a1放在proglogue的堆栈中...必须生成额外的代码行来处理alloca

   0: 1cfcb6c8                 push %fp
   4: 230a3700                 mov  %fp,%sp
   8: 24593c9c                 sub3 %sp,%sp,50 # Only one array put on stack
   c: 240a07c0                 mov  %r4,%blink
  10: 220a0000                 mov  %r2,%r0
  14: 218a0406                 mov  %r1,0x190       # Extra for alloca()
  18: 2402305c                 sub  %sp,%sp,%r1     # Extra for alloca()
  1c: 08020000r                bl   _stkchk         # Extra for alloca()
  20: 738b                     mov_s    %r3,%sp # Extra, r3 to access write via pointer
  22: 1b9cbf98 0000dead        st   0xdead,[%fp,0xffff_fe70]        ; 0xdead
  2a: 22400280                 add  %r0,%r2,10
  2e: a300                     st_s %r0,[%r3] # r3 to access write via pointer
  30: 270a3100                 mov  %blink,%r4
  34: 240a36c0                 mov  %sp,%fp
  38: 1404341b                 pop  %fp
  3c: 7ee0                     j_s  [%blink]

此外,您将通过指针访问alloca()内存(除非有明确的编译器优化...我不知道)因此导致实际的内存访问。自动变量可能被优化为仅仅是寄存器访问,这更好......编译器可以使用寄存器着色来确定自动变量最好留在寄存器中以及它们是否需要在堆栈中。

我快速搜索了C99标准(C11是关于......我的参考文献已经过时了)。无法看到对alloca的引用,因此可能不是标准定义的函数。可能的缺点?

答案 1 :(得分:0)

如果你真的只想在堆栈中分配某些东西的3元素,那么使用alloca根本就没有意义。只有在运行时依赖于某个动态参数的变量长度,或者在同一函数中执行未知数量的此类分配时才有意义。

alloca不是标准功能,因平台而异。 C标准更倾向于引入VLA,可变长度阵列作为替代品。

答案 2 :(得分:0)

  

这与分配堆栈内存相同[...]

我觉得不太好。声明局部变量会导致在输入堆栈帧时保留内存(通过从堆栈指针中减去变量的大小并调整对齐)。

看起来像alloca(3)通过在遇到它时调整堆栈指针来工作。请注意手册页的“错误”部分。

  

alloca()依赖于机器和编译器; 不鼓励使用它。

     

alloca()稍微不安全,因为它无法确保返回的指针指向有效且可用的内存块。所做的分配可能会超出堆栈的范围,甚至可能会进一步进入内存中的其他对象,而alloca()无法确定这样的错误。避免使用大量无界分配的alloca()。

这两点在我看来总结如下:

请勿使用ALLOCA