分配的变量引用在哪里,在堆栈中还是在堆中?

Posted

技术标签:

【中文标题】分配的变量引用在哪里,在堆栈中还是在堆中?【英文标题】:Where is allocated variable reference, in stack or in the heap? 【发布时间】:2010-10-26 19:19:07 【问题描述】:

我有一个问题

例如,当我在方法中声明变量时发生了什么。

无效我的方法() 运送 myShip = new Ship();

myShip 引用分配在哪里,在堆栈中还是在堆中?

我在堆栈中思考,但我很困惑,因为我正在阅读 J2ME 游戏编程书 "Java 类被实例化到 Java 堆上"

所有java类?

提前致谢

【问题讨论】:

这个问题有点不清楚。它可能是“对 myShip 的引用存储在内存中的什么位置?”或“myShip 指向的对象存储在内存中的什么位置?”前者的概念性答案是堆栈,后者的概念性答案是堆,排除优化和疯狂的实现,并且有两种方式的答案。 【参考方案1】:

myShip是对Ship对象的引用,myShip在方法调用栈上,称为“栈”。当一个方法被调用时,一块内存被压入栈顶,该内存块有空间用于该方法的所有基元(int、float、boolean 等)和对象引用,其中包括方法参数。堆是为实际对象分配内存的地方。

所以myShip 在堆栈上,Ship 对象在堆上。

注意每个线程都有自己的堆栈但共享堆。

【讨论】:

【参考方案2】:

Java 的做法确实有点不同。 reference 基本上在堆栈上。对象的内存在堆中分配。但是,可分配内存的实现方式与 C/C++ 模型中堆的实现方式不太一样。

当您像这样创建一个新对象时,它会有效地将名称放入该范围的引用表中。这很像 C++ 中指向对象的指针。当它超出范围时,该引用将丢失;分配的内存不再被引用,可以被垃圾回收。

【讨论】:

如果它只是Ship ship; 怎么办?这意味着船舶引用在堆栈上,但没有创建对象。但这是否意味着此时 Ship 类已加载完毕? 真的吗?我认为这样做会创建一个用 null 初始化的 Ship 引用。有区别吗? @CharlieMartin:你错了, Ship ship; 不要建造 Ship!该变量刚刚初始化为 null。 如果它是一个局部变量(即方法中的变量),它不会初始化为null,除非你明确地将它设置为null 我确实测试了代码:Ship ship; System.out.println(""+ship)" 并且它的事件没有使用 javac 1.8.0_31 编译它告诉我“船可能没有被初始化”所以我认为@Bombe 是正确的【参考方案3】:

目前,所有 Java 对象都在堆上分配。有传言说 Java 7 可能会进行逃逸分析并能够在堆栈上分配,但我不知道该提案是否最终确定。 Here's the RFE.

编辑:显然是already in early builds of JDK 7。 (文章说它也会在JDK 6u14中,但我找不到确认。)

【讨论】:

转义分析不会影响代码的语义,但是,我们永远不需要依赖或假设它的存在。 @bdonlan:正确,但是逃逸分析(从 Java SE 6u23 开始实施,顺便说一句)确实有助于今天的 Java 不再是 15 年前的跛脚鸭。【参考方案4】:

从概念上讲,对象在“堆”上。然后,因为它是方法本地引用,所以实际引用将在堆栈上。 “the”堆栈,我们指的是至少在 Sun 的 VM 的情况下,本机线程堆栈(即 C 中的局部变量将被分配的同一堆栈),但我认为这实际上不是一个要求(JVM只需要在每个方法调用上分配一些抽象的“堆栈帧”概念,无论是否来自本机堆栈)。

但是...在现代虚拟机上(公认的可能是更简单的嵌入式/mpbile 虚拟机除外),实际上没有“堆”这样的东西。在实践中,有各种堆区域。 其中最简单的通常几乎就像一个“迷你堆栈”,旨在快速分配那些不会长时间徘徊并且可能几乎可以立即解除分配的对象。

正如另一张海报所提到的,高度优化的 JVM可以在原则上在堆栈上分配对象数据,并且对此有明确的建议。虽然,正如其中一个参考文献中提到的那样,对此的批评是快速“伊甸园”堆几乎就像一个堆栈(只是不是“那个”堆栈)。

【讨论】:

以上是关于分配的变量引用在哪里,在堆栈中还是在堆中?的主要内容,如果未能解决你的问题,请参考以下文章

引用类型和值类型的区别

Java中“==”与equals通俗易懂篇

C#资源回收总结

java中==和equal的区别

编程语言中的值数据类型和引用数据类型之间的区别

java类中成员变量初始化后存放在堆内存中还是栈内存中?