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

以非完全编译语言(如Java)存储在堆与堆栈上的变量?,java,heap-memory,dynamic-memory-allocation,bytecode,stack-memory,Java,Heap Memory,Dynamic Memory Allocation,Bytecode,Stack Memory,我正在学习Java并阅读方法中定义的原语是如何存储在堆栈上的,而不是存储在堆上的其他东西 但是,Java并不是一种完全编译为可执行语言的语言,那么,存储在堆栈上的东西意味着什么呢 我认为JVM在读取字节码时,必须使用malloc/new/etc为所有内容获取存储 类似Python这样的语言也是如此,尽管我还没有读到Python在堆栈上存储变量的任何地方,所以我并不感到困惑。由于这些语言是解释的,当遇到变量定义时,解释器必须为其动态分配内存,对吗?语言只是一种抽象。只要提供语言规范指定的结果,任何

我正在学习Java并阅读方法中定义的原语是如何存储在堆栈上的,而不是存储在堆上的其他东西

但是,Java并不是一种完全编译为可执行语言的语言,那么,存储在堆栈上的东西意味着什么呢

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


类似Python这样的语言也是如此,尽管我还没有读到Python在堆栈上存储变量的任何地方,所以我并不感到困惑。由于这些语言是解释的,当遇到变量定义时,解释器必须为其动态分配内存,对吗?

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

当有人说原语存储在堆栈上,对象存储在堆上时,他们真正的意思是这是实现解释器的自然方式。实际上,您很可能使用JIT,在这种情况下,对象有时也可以存储在堆栈上。但是这些都是抽象的实现细节,所以您不必关心它。如果您这样做,您需要了解您正在使用的特定VM是如何工作的

Java不是一种完全编译为可执行语言的语言,那么它是什么呢 要存储在堆栈上的东西的含义是什么

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

我认为JVM在读取字节码时会 必须使用malloc/new/etc获得所有存储空间

为了在堆栈上分配数据,通常根据堆栈体系结构向前或向后移动堆栈指针。 例如,在MASM语法中,为了分配一个大小为4字节的整数,您需要从堆栈指针中减去4字节:

sub esp,4 //sub = subtract , esp = extended stack pointer
我为什么要告诉你这些?因为当JIT看到

int x; //or intermidiate language equivilant
它可以将其转换为

sub esp,4
因此,在堆栈上分配整数

但我想我知道这种困惑是从哪里来的。 堆栈和堆分配都在运行时完成

< > C和C++堆栈分配大小中唯一的例外是静态的——大小是在编译时确定的,在这里动态分配大小被确定或在运行时可以改变。
JIT在运行时编译代码,但它将堆栈分配的大小硬编码到可装配代码中,因此大小是静态的。

堆栈只是以某种方式管理的内存区域。该规范不需要特定的分配策略,但最终,JVM总是必须以任何一种方式分配所需的内存,而不管要执行的代码是编译的还是解释的

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

但看起来,你对堆栈的理解是错误的。包括Java在内的大多数现代编程语言都以框架的形式组织堆栈。帧能够容纳所有局部变量和方法中可能遇到的最深的操作数堆栈。方法的帧在方法的入口分配,并且在执行或解释方法字节码的过程中不执行进一步的分配

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


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

这只是意味着字节码解释器必须提供与堆栈上存储的变量相同的语义。通常您会创建一个名为stack的变量,并将变量存储在那里。这很容易。Java甚至有一个Deque类,用于实现堆栈的方法: