堆栈的目的是什么?我们为什么需要它?

时间:2011-10-24 11:58:07

标签: c# .net vb.net cil .net-assembly

所以我现在正在学习MSIL来学习调试我的C#.NET应用程序。

我一直想知道:堆栈的目的是什么?

只是将我的问题放在上下文中:
为什么从内存转移到堆栈或“加载?” 另一方面,为什么会从堆栈转移到内存或“存储”? 为什么不将它们全部放在内存中?

  • 是因为它更快吗?
  • 是因为它是基于RAM的吗?
  • 为了效率?

我正在努力掌握这一点,以帮助我更深入地理解CIL代码。

7 个答案:

答案 0 :(得分:433)

答案 1 :(得分:86)

请记住,当您谈论MSIL时,您正在谈论虚拟计算机的说明。 .NET中使用的VM是基于堆栈的虚拟机。与基于寄存器的VM相反,Android操作系统中使用的Dalvik VM就是一个例子。

VM中的堆栈是虚拟的,由解释器或即时编译器将VM指令转换为在处理器上运行的实际代码。在.NET的情况下几乎总是一个抖动,MSIL指令集被设计为从一开始就被jitted。例如,与Java字节码相反,它具有针对特定数据类型的操作的不同指令。这使得它被优化以进行解释。实际上存在MSIL解释器,它在.NET Micro Framework中使用。哪个在资源非常有限的处理器上运行,无法承受存储机器代码所需的RAM。

实际的机器代码模型是混合的,具有堆栈和寄存器。 JIT代码优化器的一个重要工作是提出一种方法来存储寄存器中保存在堆栈中的变量,从而大大提高执行速度。 Dalvik抖动有相反的问题。

机器堆栈是一个非常基本的存储设施,已经在处理器设计中存在了很长时间。它具有非常好的参考局部性,这是现代CPU的一个非常重要的特性,它比RAM可以提供数据并且支持递归更快地咀嚼数据。语言设计受到堆栈的影响很大,可见支持局部变量和范围仅限于方法体。堆栈的一个重要问题是该站点的名称。

答案 2 :(得分:20)

有一篇非常有趣/详细的维基百科文章 Advantages of stack machine instruction sets 。我需要完全引用它,所以简单地放一个链接就更容易了。我只想引用子标题

  • 非常紧凑的对象代码
  • 简单的编译器/简单的口译员
  • 最小处理器状态

答案 3 :(得分:8)

向堆栈问题添加更多内容。堆栈概念源自CPU设计,其中算术逻辑单元(ALU)中的机器代码对位于堆栈上的操作数进行操作。例如,乘法运算可以从堆栈中取两个顶部操作数,将它们多个并将结果放回堆栈。机器语言通常有两个基本功能来添加和删除堆栈中的操作数;推和POP。在许多cpu的dsp(数字信号处理器)和机器控制器(例如控制洗衣机的控制器)中,堆栈位于芯片本身上。这样可以更快地访问ALU,并将所需的功能整合到单个芯片中。

答案 4 :(得分:5)

如果没有遵循堆栈/堆的概念并且数据被加载到随机存储器位置或者数据是从随机存储器位置存储的......它将是非结构化的并且是非托管的。

这些概念用于在预定义的结构中存储数据,以提高性能,内存使用......因而称为数据结构。

答案 5 :(得分:4)

通过使用continuation passing style编码,可以让系统在没有堆栈的情况下工作。然后调用帧成为垃圾收集堆中分配的延续(垃圾收集器需要一些堆栈)。

见Andrew Appel的旧着作:Compiling with ContinuationsGarbage Collection can be faster than Stack Allocation

(由于缓存问题,他今天可能有点不对劲)

答案 6 :(得分:0)

我正在寻找“中断”,没有人将其作为优势。对于每一个中断微控制器或其他处理器的设备,通常都会将寄存器压入堆栈,调用中断服务程序,完成后,将这些寄存器从堆栈中弹出,并放回它们的位置。是。然后恢复指令指针,正常活动从中断处开始,几乎就像中断从未发生过一样。有了堆栈,实际上(理论上)您可以让多个设备互相中断,并且由于堆栈的缘故,它们都可以正常工作。

还有一系列基于堆栈的语言,称为concatenative languages。它们都是(我相信)功能语言,因为堆栈是传入的隐式参数,而且更改后的堆栈是每个函数的隐式返回。 ForthFactor(非常好)都是例子,还有其他例子。 Factor已与Lua相似地用于脚本游戏,并且由目前在Apple工作的天才Slava Pestov编写。我看过他的Google TechTalk on youtube几次。他谈到Boa构造函数,但我不确定他是什么意思;-)。

我真的认为,当前的某些VM(例如JVM,Microsoft的CIL,甚至我看到的是为Lua编写的VM)也应该以其中一些基于堆栈的语言编写,以使其可移植到更多领域。平台。我认为这些连接语言在某种程度上缺少了作为VM创建工具包和可移植性平台的调用。甚至还有pForth,它是用ANSI C语言编写的“便携式” Forth,可用于更通用的可移植性。有人尝试使用Emscripten或WebAssembly对其进行编译吗?

使用基于堆栈的语言,有一种称为零点的代码样式,因为您可以仅列出要调用的函数,而不必(有时)不传递任何参数。如果这些函数完美地结合在一起,那么您将只有所有零点函数的列表,并且从理论上讲就是您的应用程序。如果您深入研究Forth或Factor,您将了解我在说什么。

Easy Forth,这是一个用JavaScript编写的不错的在线教程,下面是一个小示例(请注意“ sq sq sq sq”作为零点调用样式的示例):

: sq dup * ;  ok
2 sq . 4  ok
: ^4 sq sq ;  ok
2 ^4 . 16  ok
: ^8 sq sq sq sq ;  ok
2 ^8 . 65536  ok

此外,如果您查看Easy Forth网页的源代码,则会在底部看到它是非常模块化的,用大约8个JavaScript文件编写。

我几乎花了很多钱才能尝试吸收Forth,可以尝试吸收它,但是现在我才开始更好地理解它。我想跟进来的人,如果您真的想要得到它(我发现这太晚了),请下载关于FigForth的书并实现它。商业化的Forth太复杂了,而Forth的最大优点是可以从上到下理解整个系统。不知何故,Forth在新处理器上实现了整个开发环境,尽管为此的需求似乎已经随C一起通过了,但作为从头开始编写Forth的通行仪式仍然有用。因此,如果您选择执行此操作,请尝试一下FigForth书-这是在各种处理器上同时实现的几个Forth。一种罗塞塔石碑。

为什么我们需要堆栈-效率,优化,零点,在中断时保存寄存器,对于递归算法来说,它是“正确的形状”。