0%

【翻译】基于栈(stack)的内存分配

译者注:国内很多人对这两个词语的翻译总是让人糊涂的,这里译者统一做如下翻译,stack统一翻译为栈,而heap统一翻译为堆。

基础

计算体系结构中的栈是内存的区域,在其中以后进先出(LIFO)的方式添加或删除数据。

在大多数现代计算机系统中,每个线程都有一个保留的内存区域,称为其栈。 当函数执行时,它可能会将一些状态数据添加到栈的顶部; 当函数退出时,它负责从栈中删除该数据。 至少,线程的栈用于存储函数调用的位置,以允许return语句返回到正确的位置,但是程序员可以进一步选择显式使用栈。 如果内存区域位于线程的栈上,则表示该内存已分配在栈上,即基于栈的内存分配。

stack会有以下信息

  • 局部变量
  • 函数参数
  • 返回地址

由于以后进先出的方式添加和删除数据,因此基于栈的内存分配非常简单,并且通常比基于堆的内存分配(也称为动态内存分配)快。 另一个功能是,当函数退出时,栈上的内存会自动高效地回收,如果不再需要数据,这对程序员来说很方便。(如果longjmp移到了调用alloca之前的某个点,同样适用于longjmp。)但是,如果数据需要以某种形式保存,则必须在函数退出之前从栈中复制数据。 因此,基于栈的分配适用于临时数据或在创建函数退出后不再需要的数据。

在某些小型CPU上,线程分配的栈大小可能只有几个字节。 在栈上分配的内存多于可用内存,可能会由于栈溢出而导致崩溃。 这也是为什么通常使用alloca的函数被禁止进行内联的原因:如果将这样的函数(译者注:指使用了alloca的函数)内联到循环中,则调用方将遭受栈使用率意外增长的困扰,从而更有可能发生溢出(译者注:stack overflow,栈溢出)。

基于栈的分配可能还会导致较小的性能问题:它导致可变大小的栈帧,因此需要管理栈指针和帧指针(对于固定大小的栈帧,其中之一是冗余的)。 通常,这至少比调用malloc和free便宜得多(译者注:这里是说基于stack的内存分配比使用malloc和free在堆上的内存分配便宜很多)。

操作的系统接口

许多类似Unix的系统以及Microsoft Windows都实现了一个称为alloca的功能,该功能以类似于基于堆的malloc的方式动态分配堆内存。 编译器通常将其转换为处理堆指针的内联指令,类似于如何处理可变长度数组。尽管不需要显式释放内存,但由于堆溢出,存在未定义行为的风险。 该功能早在Unix系统上就已存在于32 / V(1978),但它不是标准C或任何POSIX标准的一部分。

原文地址:https://en.wikipedia.org/wiki/Stack-based_memory_allocation