以非完全编译语言(例如Java)存储在堆与堆栈上的变量?

时间:2015-11-15 19:27:02

标签: java stack heap bytecode dynamic-allocation

我正在学习Java并阅读原语(在方法中定义)如何存储在堆栈上,"与存储在"堆上的其他东西相比。"

但是,Java并不是一个完全编译成可执行语言的东西,那么对于存储在"堆栈"?

上的东西意味着什么呢?

我认为JVM在读取字节码时,必须使用malloc / new / etc来获取所有内容。

对于像Python这样的语言也是如此(虽然我没有读过Python在堆栈上存储变量的地方,所以对我来说没有混淆)。由于这些语言被解释,解释器在遇到变量定义时,必须为它动态分配内存,对吗?

3 个答案:

答案 0 :(得分:0)

语言只是一种抽象。只要它提供了语言规范规定的结果,就允许任何实现。

当有人说基元存储在堆栈上并且对象存储在堆上时,它们的真正含义是这是实现解释器的自然方式。在实践中,您很可能正在使用JIT,在这种情况下,对象有时也可以存储在堆栈中。但这都是抽象的实现细节,所以你不必关心它。如果这样做,您需要了解您使用的特定虚拟机的工作原理。

答案 1 :(得分:0)

  

Java不是完全编译成可执行语言,所以它是什么   对于要存储在“堆栈”中的东西意味着什么?

不是第一步。但是当你开始运行你的Java程序时,JIT会将代码编译成机器语言。如果没有,你就不能运行任何Java程序。任何程序都应该转动或使用现有的机器代码才能运行。

  

我认为JVM在读取字节码时会   必须使用malloc / new / etc。

来获取所有内容

为了在堆栈上分配数据,您(通常)向前或向后移动堆栈指针(取决于堆栈架构)。 例如,在MASM语法上,为了分配1个大小为4个字节的整数,你从堆栈指针中减去4个字节:

sub esp,4 //sub = subtract , esp = extended stack pointer

为什么我告诉你这一切?因为当JIT看到像

这样的东西时
int x; //or intermidiate language equivilant

它可以将其转换为

sub esp,4

因此在堆栈上分配整数。

但我认为我认识到混乱来自何处 堆栈和堆分配都在运行时完成

C(和C ++)堆栈分配大小是静态的唯一例外 - 大小是在编译时确定的,其中动态分配大小在运行时确定(或可以更改)。 JIT在运行时编译代码,但它将堆栈分配的大小硬编码到可置信代码中,因此大小是“静态的”。

答案 2 :(得分:0)

堆栈只是以某种方式管理的内存区域。规范不需要特定的分配策略,但最终,JVM 始终必须以任一方式分配所需的内存,无论要执行的代码是否已编译或被解释

这与使用直接编译为本机代码的编程语言开发的程序没有什么不同。程序仍然必须为堆栈分配内存,尽管它可能发生在幕后(在Java中它也发生在应用程序员的角度来看幕后)。

但看起来,无论如何你对堆栈有错误的想法。大多数现代编程语言(包括Java)在 frames 中组织堆栈。一个框架能够保存所有局部变量以及您在方法中可能遇到的最深操作数堆栈。方法的框架在方法的条目处分配,并且在执行或解释方法的字节代码的过程中不会执行进一步的分配。

或者,换句话说,Java的字节码指令集没有处理“变量定义”这样的东西。只有在局部变量(由索引寻址)和操作数堆栈之间或在操作数堆栈和堆之间传输项的指令。已经写入的内容暗示了局部变量的存在。有可选的调试信息,暗示哪些变量应存在于哪个代码位置,但这些信息在正常执行期间不会得到处理。

根据JVM实现,每个线程可能具有预先分配的固定最大堆栈大小的内存存储,其中放置堆栈帧。在这些实现中,在线程的生命期间不对堆栈执行操作系统操作意义上的分配。许多本机代码遵循相同的模型。