Java中的对象能否存储在堆栈而非堆中?

14

一个对象能够被存储在堆栈上而非堆内存中吗?

我最近看了这篇博客http://www.programmerinterview.com/index.php/data-structures/difference-between-stack-and-heap/

一个对象能够被存储在堆栈上而非堆内存中吗?

是的,一个对象可以被存储在堆栈上。如果你在函数内创建一个对象时没有使用“new”操作符,那么它将会被创建并存储在堆栈上,而不是堆内存中。假设我们有一个名为Member的C++类,我们想要创建一个对象。我们也有一个名为somefunction()的函数。下面是代码示例:

他们建议对象可以存储在堆内存中,这让我感到困惑。

我认为:

  1. 所有Java对象都存储在堆内存中。
    无论是通过以下方式创建:
    a. new关键字
    b. 使用Class.forName()方法
    c. 使用clone()方法
    d. 使用newInstance()方法
    e. 使用对象反序列化。

  2. 方法、线程和变量都在堆栈上。

  3. 类变量(静态变量)作为与该类相关的Class对象的一部分存储。这个Class对象只能由JVM创建,并存储在永久代中。

如果我错了,请纠正我。

现在我的疑问是,任何形式的对象是否可以驻留或存储在堆栈上。

谢谢。


一个对象可以被存储在栈上而不是堆上吗?是的,一个对象可以被存储在栈上。如果你在函数内部创建一个对象而不使用“new”运算符,那么这将在栈上创建和存储对象,而不是在堆上。假设我们有一个名为Member的C++类,我们想要创建一个对象。我们还有一个名为somefunction()的函数。下面是代码示例: - user_vs
你应该把这个放在你的问题里,而不是评论中。 - Pshemo
4
他们的采访是关于C++,你在问有关Java的问题。这是两种完全不同的编程语言。 - RealSkeptic
他们正在讨论Java及其JVM相关的事情。 - user_vs
3
不,他们讨论了各种语言。你所提到的例子是C++。"......其他像Java和.NET这样的语言使用垃圾回收来自动删除堆内存......" - Andreas Fester
显示剩余2条评论
4个回答

7

所有类实例均存储在堆中。

以下是一些可靠的来源:
JVM规范:
https://docs.oracle.com/javase/specs/jvms/se8/jvms8.pdf

2.5.3 堆

Java虚拟机具有一个堆,该堆在所有Java虚拟机线程之间共享。堆是运行时数据区, 用于分配所有类实例和数组的内存。

来自Java语言规范:
https://docs.oracle.com/javase/specs/jls/se8/jls8.pdf

17.4.1 共享变量

可以在线程之间共享的内存称为共享内存或堆内存。所有实例字段、静态字段和数组元素都存储在堆内存中。


6
您的观点(1):所有对象都分配在堆上。 这基本上是正确的。对象总是分配在堆上。但是,如果逃逸分析允许它(它仅对调用方法可见,并且不会逃逸到外部),则对象可能会在堆栈上分配,如IBM网站上讨论的此文章中所述。
然而,请注意Oracle明确表示,它不会因为逃逸分析而使用堆栈分配来替换堆分配,详见这篇技术说明
因此,在(Oracle)Java中,对象始终在堆上。
您的观点(2):方法、线程和变量都在堆栈上。 不,方法和线程不在堆栈上。局部变量和参数放置在堆栈上。在每次方法调用时,将准备一个堆栈帧,并为参数、返回值和局部变量分配空间。
方法本身是类的一部分。线程对象像任何其他对象一样分配,但线程本身不是数据,也没有被分配,而是为它们分配堆栈。
您的观点(3):静态变量分配在PermGen上。 这个信息在Java 8之前是正确的。根据JEP 122,它们现在分配在堆上,因为PermGen已被消除。
请注意,这种实现细节在不同的JVM实现之间是不同的。其他JVM甚至在Java 8之前就已经摆脱了PermGen。

2

你引用的评论指的是C++,它可以在堆栈上存储对象。但在Java中,你不能这样做。


2
所有的Java对象都必须在堆中被分配:
《Java虚拟机规范》第8版2.5.3节:
“……堆是运行时数据区域,用于分配所有类实例和数组的内存。”
然而,由于逃逸分析,一些对象可能会被优化为原始类型并存储在栈上。在这种情况下,它们实际上从未成为对象,因此不会真正违反这个规则。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接