如何使用堆栈内存?

时间:2017-07-17 05:53:19

标签: c# memory-management stack

在堆栈中,存储器可以以LIFO方式存储  我将向您展示一个清楚解释我的问题的例子

public static void main()
{
  int i=0;
  char ch='a';
  string s="doubt";
}

在上面的例子中,第一个堆栈存储'i'值,并存储在'store'值的顶部,并存储在''值'商店的顶部。现在的问题是,如果我想使用'i'值,它怎么能弹出来。如果它弹出所有变量以获得int'i'值,那么's'和'ch'值可以存储在哪里

2 个答案:

答案 0 :(得分:1)

Java实现通常将源代码编译为某个JVM字节码。 C#实现针对CLI进行编译,即CLR名为CIL的字节码。

JVM bytecode用于基于堆栈的计算机。 CIL字节码也是stack-based。所以JVM和& CIL字节码以某些stack machine为目标(但对于Java -i.e.JVM-和C#-i.e.CIL - 则不同)。

编译器会计算局部变量集并生成适当的指令来处理call stack中的当前帧。

从概念上讲,当控制流离开block声明它时,会弹出局部变量的槽(在当前调用帧中)(但实际上发生的是实现细节)。阅读scope。所以你不需要显式地弹出任何值(编译器会处理嵌套的作用域和局部变量)。

通常,在function prologue中调用期间会调用(在调用堆栈上)调用帧,并在(对应的)函数结尾中弹出(来自调用堆栈),但详细信息取决于{ {3}}

JVM需要calling conventions,CIL也需要garbage collector。它将扫描堆栈上的指针(对象)(在您的示例中为s

BTW,Java有一些reflection工具(不适用于新手)可以访问调用堆栈。见this。 C#(和CIL)也提供reflection。另请阅读continuations

调用堆栈确实是遵循stack规则的last-in first-out,但是拉取和弹出操作是调用协议的一部分,并且是编译器生成的,因此保持隐式。在呼叫期间,在呼叫栈上推送新的呼叫帧。返回时,它会从调用堆栈中弹出。另请阅读tail-calls(然后在通话时新呼叫帧替换当前的呼叫帧);遗憾的是,JVM一般不支持尾调用。

我建议阅读SICP,其中有一些章节解释了这些概念。它是一个优秀的免费可用的编程介绍(使用Java或C#作为其编程语言)。

答案 1 :(得分:1)

  

在上面的示例中,第一个堆栈存储'i'值,并存储在'store'值的顶部,并存储在''值'商店的顶部。

正确。请注意,您没有说'推',这是不正确的。

  

现在的问题是,如果我想使用'i'值,它怎么能弹出来。

它不是'弹出'。它是通过当前堆栈帧基础的索引访问的。

  

如果弹出所有变量以获得int'i'值

没有。

  

可以存储's'和'ch'值的位置

在堆栈上,或者更好地在当前堆栈帧中。

您应该将堆栈视为堆栈 frames 的堆栈,每个方法调用一个,而不是作为值堆栈。