当前位置: 首页 > 知识库问答 >
问题:

为什么alloca不检查它是否可以分配内存?

终祯
2023-03-14

为什么alloca不检查它是否可以分配内存?

摘自Man 3 Alloca:

如果分配导致堆栈溢出,则程序行为未定义。…如果无法扩展堆栈帧,则没有错误指示。

现在alloca(s)brk都返回一个指针,指向新分配的内存的开始,这意味着它们都必须知道堆栈/堆在当前时刻的结束位置。实际上,来自城域网2 SBRK:

调用增量为0的sbrk()可以用来查找程序中断的当前位置。

因此,按照我的理解,检查alloca是否可以分配所需的内存,本质上归结为检查堆栈的当前末端和堆的当前末端之间是否有足够的空间。如果在堆栈上分配所需的内存会使堆栈到达堆,则分配失败;否则,它就成功了。

void *safe_alloca(size_t size)
{
    if(alloca(0) - sbrk(0) < size) {
        errno = ENOMEM;
        return (void *)-1;
    } else {
        return alloca(size);
    }
}

brk()将数据段的结尾设置为addr指定的值,当该值合理时,系统有足够的内存,并且进程不超过其最大数据大小(参见setrlimit(2))。

那么,如果(s)BRK可以进行这样的检查,那么为什么Alloca不能呢?

共有1个答案

海叶秋
2023-03-14

Alloca是一个非标准的内部编译器,其卖点是编译成非常轻量级的代码,甚至可能是单个指令。它基本上是用局部变量执行每个函数开始时执行的操作-将堆栈指针寄存器移动指定的量并返回新值。与SBRK不同,Alloca完全位于userspace中,无法知道还有多少堆栈可用。

堆栈向堆增长的图像对于学习内存管理的基础知识是一个有用的心理模型,但在现代系统中并不真正准确:

  • 正如cmaster在他的回答中解释的那样,堆栈大小将主要受到内核实施的限制的限制,而不是堆栈实际上与堆发生冲突的限制,尤其是在64位系统上。
  • 在多线程进程中,没有一个堆栈,而是每个线程有一个堆栈,而且它们显然不能都朝着堆增长。
  • 堆本身不是连续的。现代的malloc实现使用多个竞技场来提高并发性能,并将大量分配卸载到匿名的mmap,确保free将它们返回到OS。后者也在传统描述的单竞技场“堆”之外。
 类似资料:
  • 由分配的内存可以用重新分配。有类似的函数吗?当您不希望在堆上分配内存,并且需要多次分配可变堆栈内存(例如在库函数中,您需要动态内存,但不希望在堆上分配)时,重新分配堆栈内存可能很有用,因为库的用户可能使用自定义的堆分配策略。它看起来是这样的: 重要的是,这一切都发生在堆栈上。问:有重新分配动态堆栈内存的方法吗?

  • 问题内容: 假设我有一个Python函数和。旨在以递归方式调用自身。不应递归调用。有没有办法确定是否已递归调用它? 问题答案: 为此使用追溯模块: 因此,如果堆栈中的任何条目指示从调用了代码,则该调用是(间接)递归的。该方法使您可以轻松访问此数据。下面的示例中的语句仅计算函数名称的完全匹配数。为了使它更漂亮(感谢agf的想法),您可以将其变成装饰器:

  • 在C语言中,alloca()函数在alloca()调用方的stackframe上分配内存。 当您试图分配大量它无法分配的字节时,会发生什么? null 有人有更多关于这方面的信息吗?

  • 例如,我知道在检查字符串时,可以执行如下操作 但是是否有一种方法来检查一个字符是否匹配一个可能性列表?或者我必须逐一检查,例如 ...等。

  • 问题内容: 我知道我可以这样做: 然后只需编写语句中所需的代码。 还有其他方法可以检查它们是否相等? 问题答案: 怎么了 if(!Arrays.equals(array1,array2)) 与相同,即是同一数组。这不是大多数人期望的。 比较数组的内容。

  • 问题内容: 我想知道是否有一个gcc宏可以告诉我Linux内核版本,以便我可以适当地设置变量类型。如果没有,我将如何定义自己的宏呢? 问题答案: 在 LINUX / version.h中 的文件有一个名为宏可以让你检查要对当前的Linux版本头(版本)安装。例如,检查当前的Linux标头是否适用于内核 v2.6.16 或更早版本: 在运行时获取版本信息的更好方法是使用include / linux