因此,我们知道Stack的工作原理是LIFO。 例如,我们有这个代码(由Java编写,但我认为语言并不重要):
int a = 1;
int b = 2;
int c = 3;
System.out.println(a);
据我所知,首先将被推入堆栈,然后是b,然后是c。 但是在最后一行需要解决的值,stack只支持push和pop操作。这是否意味着为了解析a的值,以前的值会弹出(编辑)?
它真的很快吗?
答案 0 :(得分:2)
模拟的CPU和VM使用的堆栈数据结构(包括JVM)不是<li class="col">
<a href="{% url 'aboutme' %}">
<div class="skillsIcon">
<div class="ninja">
</div>
</div>
</a>
</li>
的堆栈(或者任何特定的数据类型)。它是一堆所谓的堆栈帧,它包含当前方法的所有局部变量和参数。
Java在编译时决定方法堆栈帧的布局,并在运行时使用此信息在输入方法时创建新的堆栈帧,并从现有堆栈帧访问局部变量。
虽然堆栈确实支持一次推送和弹出一个项目,因为&#34;项目&#34;在这种情况下是一个堆栈框架,它包含运行方法的所有三个局部变量。
答案 1 :(得分:2)
这种堆栈与LIFO数据结构不同。
这种情况下的堆栈是指堆栈帧,它包含将使用该函数的所有局部变量以及调用者的返回地址。这些变量在内部通过堆栈帧指针的地址偏移进行访问。根据调用约定,可以将参数传入和传出堆栈帧,但在某些情况下可能会使用寄存器。
每当调用一个函数时,都会创建一个新的堆栈帧并将其推送到程序堆栈(或多线程程序中的线程堆栈)之上。由于每个单独的帧都具有堆栈语义,因此您通常只能访问当前函数范围内的变量。 (我通常说,因为你可以通过偏移指向当前堆栈帧中数据的指针来回避它,但这样做依赖于编译器,可能会产生灾难性的后果)
当函数返回时,弹出堆栈帧并从堆栈的新顶部继续执行。所以从这个意义上讲,它仍然保留了你所熟悉的LIFO语义。
通常,堆栈帧上的数据是静态的,但有时(例如C中的一些非标准函数)您可以直接在堆栈上分配数据。这就是为什么C数组必须是已知大小的原因,因为它们实际上存储在堆栈中。
数组和其他数据结构通常存储在堆上,这是用于动态分配数据的另一个内存区域(在C中,这将是由malloc
创建的任何内容;在Java / C ++,这将是使用new
创建的任何内容。堆栈上的数据实际上只是堆上数据的指针/引用,这就是为什么您可以将new
ed数据返回给调用者没有直接复制它。
答案 2 :(得分:0)
堆栈不仅支持推送和弹出操作。您在堆栈上为这些变量分配空间,然后填充这些值,并在必要时可以读取/交互。
在现代的,高性能的语言中,那些甚至可能根本就不在堆栈中。它们可以是寄存器。