【问题标题】:How stack values are resolved, when they are not at the top?当堆栈值不在顶部时,如何解析它们?
【发布时间】:2018-05-30 00:39:18
【问题描述】:

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

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

据我了解,首先 a 将被推入堆栈,然后是 b,然后是 c。 但是最后一行需要解析a的值,stack只支持push和pop操作。是不是说为了解析a的值,会pop(ed)之前的值?

真的很快吗?

【问题讨论】:

  • 您将堆栈混淆为数据集合,而堆栈则混淆为内存管理。堆栈数据收集按照您的设想工作,要到达第一个元素,您必须经过最后一个元素。内存管理中的堆栈是数据如何排列的表示,无需使用 LIFO 原则来访问数据。

标签: java memory stack


【解决方案1】:

这种栈与后进先出数据结构不同。

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

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

当函数返回时,堆栈帧被弹出并从新的堆栈顶部继续执行。所以从这个意义上说,它仍然保留了你熟悉的 LIFO 语义。

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

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

【讨论】:

    【解决方案2】:

    模拟的 CPU 和 VM(包括 JVM)使用的堆栈数据结构不是 ints(或任何特定数据类型)的堆栈。它是一个所谓的栈帧的栈,里面保存着当前方法的所有局部变量和参数。

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

    虽然堆栈确实支持一次推送和弹出一个项目,因为在这种情况下,“项目”是一个堆栈框架,其中包含运行方法的所有三个局部变量。

    参考:Contents of Stack Frame in Java

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-03-20
        • 2010-10-19
        • 2012-01-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-04
        相关资源
        最近更新 更多