繁体   English   中英

当堆栈值不在顶部时如何解决?

[英]How stack values are resolved, when they are not at the top?

因此,众所周知,Stack是按照LIFO原理工作的。 例如,我们有以下代码(由Java编写,但是我认为语言并不重要):

int a = 1;
int b = 2;
int c = 3;
System.out.println(a);

据我了解,首先a将被推入堆栈,然后b,然后c。 但是最后一行需要解决的价值,堆栈仅支持推入和弹出操作。 这是否意味着要解析a的值,将弹出先前的值?

真的快吗?

由CPU和VM(包括JVM)进行仿真的堆栈数据结构不是int的堆栈(就此而言,不是任何特定的数据类型)。 它是所谓的堆栈框架的堆栈 ,其中包含当前方法的所有局部变量和参数。

Java在编译时决定方法的堆栈框架的布局,并在运行时使用此信息在输入方法时创建新的堆栈框架,并从现有堆栈框架访问局部变量。

尽管堆栈确实支持一次推送和弹出一个项目,但是由于“ item”在此情况下是一个堆栈框架,其中包含运行方法的所有三个局部变量。

参考: Java中堆栈框架的内容

这种堆栈与LIFO数据结构不同。

在这种情况下, 堆栈是指一个堆栈框架 ,其中包含该函数将使用的所有局部变量以及到调用方的返回地址。 这些变量在内部使用堆栈帧指针的地址偏移进行访问。 根据调用约定,尽管在某些情况下可能会使用寄存器,但参数可能会传入和传出堆栈帧。

每当调用函数时,都会创建一个新的堆栈框架并将其压入程序堆栈(或多线程程序中的线程堆栈)的顶部。 由于每个单独的框架都有堆栈语义,因此这就是为什么您通常只能访问当前函数范围内的变量的原因。 (我通常这样说,因为您可以通过偏移当前堆栈帧中数据的指针在C中回避它,但是这样做是依赖于编译器的,并且可能会造成灾难性的后果)

当函数返回时,将弹出堆栈框架,并从新的堆栈顶部继续执行。 因此,从这个意义上讲,它仍然保留了您熟悉的LIFO语义。

通常,堆栈帧上的数据是静态的,尽管有时(例如,C中的某些非标准函数)您可以直接在堆栈上分配数据。 这就是为什么C数组必须为已知大小的原因,因为它们实际上存储在堆栈中。

数组和其他数据结构通常存储在堆上 ,这是用于动态分配数据的内存的另一个区域(在C中,这将是malloc创建的任何内容;在Java / C ++中,这将是使用new创建的任何内容)。实际上,堆栈上的数据只是指向堆上数据的指针/引用,这就是为什么您可以将new ed数据返回给调用方而无需完全复制它们的原因。

堆栈不只支持推入和弹出操作。 您在堆栈上为这些变量分配空间,然后填充这些值,并可以根据需要与其进行读取/交互。

在现代的高性能语言中,这些甚至可能根本不在堆栈中。 它们可以是寄存器。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM