Optimization 释放alloca分配的内存

Optimization 释放alloca分配的内存,optimization,memory-management,Optimization,Memory Management,在当前函数退出之前,是否可以显式释放C的alloca()分配的内存?如果是,如何分配?否,因为它与局部变量一起分配在堆栈上。如果需要可以显式释放的内存,请使用动态内存分配函数之一 没有一种混合方法允许您显式释放,并在函数退出时自动释放它,至少在标准中没有;如果之后发生了其他事情(如果不在汇编中写入所有内容,您就无法控制它),那么您不能仅仅收缩堆栈。因此,在离开函数的堆栈框架之前,这是不可能的 这也是为什么如果你溢出了分配的缓冲区,你会把事情搞得一团糟。您可以开始覆盖函数返回的代码的地址,导致它跳

在当前函数退出之前,是否可以显式释放C的alloca()分配的内存?如果是,如何分配?

否,因为它与局部变量一起分配在堆栈上。如果需要可以显式释放的内存,请使用动态内存分配函数之一


没有一种混合方法允许您显式释放,并在函数退出时自动释放它,至少在标准中没有;如果之后发生了其他事情(如果不在汇编中写入所有内容,您就无法控制它),那么您不能仅仅收缩堆栈。因此,在离开函数的堆栈框架之前,这是不可能的

这也是为什么如果你溢出了分配的缓冲区,你会把事情搞得一团糟。您可以开始覆盖函数返回的代码的地址,导致它跳转到其他地方,各种可怕的东西。小心

Malloc是在堆上工作的,因此它的功能更加灵活。

来源:

使用
alloca
分配块是一个显式操作;您可以根据需要分配任意多的块,并在运行时计算大小。但是,当您退出调用alloca的函数时,所有的块都会被释放,就像它们是在该函数中声明的自动变量一样无法明确释放空间。


这是可能的,但没有预先编写的函数来完成。您必须深入研究编译器的alloca()实现,找出它在做什么,然后编写自己的freea()。由于每个编译器执行alloca()的方式不同,因此必须为每个编译器重写freea()


但我觉得很难相信这是值得的麻烦。如果您需要显式释放它,只需使用malloc/free,这些函数通常都经过了大量优化。利用它们。

这对于连续传球风格(CPS)很有用,而不是真正的失球

您可以调用一个函数,该函数在将堆栈缩小到字符串长度并调用下一个函数之前,分配并操作堆栈顶部的字符串


没有任何概念上的原因可以解释为什么不能有freea(),这将是一个nop,表示除了堆栈上最顶端的条目之外的任何内容。

使用C99,您可以使用一个。只需在新范围内声明VLA;当作用域退出时,它将自动释放

例如:

int some_function(int n) {
    // n has the desired length of the array
    ...
    { // new scope
        int arr[n]; // instead of int *arr = alloca(n*sizeof(int));
        // do stuff with array
    }
    // function continues with arr deallocated
    ...
}
#include <stdio.h>
#include <alloca.h>

int main()
{
  unsigned long p0, p1, p2;
  p0=(unsigned long)alloca(0);
  p1=(unsigned long)alloca((size_t) 0x1000);
  p2=(unsigned long)alloca((size_t)-0x1000);
  printf( "p0=%lX, p1=%lX, p2=%lX\n", p0, p1, p2 );
  return 0;
}

是的,但这取决于alloca()的实现。alloca()的一个合理而简单的实现是通过调整堆栈指针将新分配的块放在堆栈顶部。因此,要释放此内存,我们只需执行分配(但您需要研究alloca()的实际实现),让我们以以下不可移植的代码为例进行验证:

int some_function(int n) {
    // n has the desired length of the array
    ...
    { // new scope
        int arr[n]; // instead of int *arr = alloca(n*sizeof(int));
        // do stuff with array
    }
    // function continues with arr deallocated
    ...
}
#include <stdio.h>
#include <alloca.h>

int main()
{
  unsigned long p0, p1, p2;
  p0=(unsigned long)alloca(0);
  p1=(unsigned long)alloca((size_t) 0x1000);
  p2=(unsigned long)alloca((size_t)-0x1000);
  printf( "p0=%lX, p1=%lX, p2=%lX\n", p0, p1, p2 );
  return 0;
}
因此我们知道实现不会验证参数-0x1000,否则无符号值将是一个非常大的整数。堆栈指针最初是0x…B89F;由于此堆栈向上增长,所以将堆栈指针up更改为(0x…B89F-0x1000)=0x…A89F。负分配(0xA89F-(-0x1000))后,堆栈指针返回0x…B89F

但是,对于gcc 4.8.3,示例输出为:

p0=7FFF2C75B89F, p1=7FFF2C75A89F, p2=7FFF2C75B89F
p0=7FFFA3E27A90, p1=7FFFA3E26A80, p2=7FFFA3E27A70
在/usr/include/alloca.h中,我们发现:

#ifdef  __GNUC__
# define alloca(size)   __builtin_alloca (size)
#endif /* GCC.  */

所以我们知道GCC4.8.3提供的内置alloca函数做了类似的事情,只是它分配额外的0x10字节作为安全裕度。在执行负分配时,它仍然假定它向上增长,因此尝试保留0x10额外字节(-0x10),以便p2=0x…6A80-(-0x1000)-0x10=0x…7A70。因此,要格外小心。

您不需要编写任何自定义的
freea(…)
类函数,也不需要使用VLA。 在C和C++中,分配给堆栈的内存可以轻松释放(C++不支持VLAs)。 alloca(…)在堆栈上分配,对吗?这意味着内存将在超出范围时被释放。。。所以只要使用范围


#include

一个可移植的实现是“void freea(void*p){}///只是假装一下”。嗯,不。你不能移动堆栈指针而不损坏,你也不能重新定位堆栈上的项,因为它们的地址可能存储在别处。free/malloc工作的原因是它们可以完全控制堆空间。您将不会像alloca()那样重新定位项目-带有地址的局部变量必须位于alloca空间之前。无论如何,你不应该将悬空指针留在空闲空间,就像你不能在空闲空间中一样。如果分配量很大,有些实现会进入堆。我知道微软有。我已经实现了alloca(),是的,你可以做一个freea()-哦,真的吗<代码>a=alloca(asize);b=alloca(b尺寸)打电话行吗?你能解释一下你的动机吗?为什么要在返回之前释放分配的空间?