Java可以在堆栈上分配列表吗?

Posted

技术标签:

【中文标题】Java可以在堆栈上分配列表吗?【英文标题】:Can Java allocate a list on stack? 【发布时间】:2014-06-10 00:20:10 【问题描述】:

每当我在java中启动一个列表时,我都会这样做

List<Integer> list = new LinkedList<>();

我假设这将在堆上分配列表。想知道我是否可以在堆栈上分配列表?

【问题讨论】:

为什么要在栈上分配? 这纯粹是学术性的吗? @LuiggiMendoza PermGen 不是堆栈内存。它是为 JVM 进程的其余部分分配预期存在的类和其他结构的地方;将这些移动到单独的空间使常规堆中的垃圾收集更加有效。随着类卸载变得越来越常规,这种效率提升变得不那么明显了。 list 在堆栈上,但这是一个引用,实际对象在堆上。 @PeterLawrey 但前提是它是局部变量。如果它是一个成员变量,它也会在堆上。 【参考方案1】:

所有对象,包括它们各自的属性,都存储在堆上。

所有局部变量及其参数都存储在堆栈中,因为它们包含原始值或引用。

但是,在特殊情况下,java 虚拟机可能会执行逃逸分析并决定在堆栈上分配对象(包括您的 LinkedList),但这通常不会发生,也不是主要问题。

一般来说,如果你在堆栈上分配一个对象,当你调用一个引用它的函数时,你会得到一个对象的副本。相反,如果您在堆上分配一个对象,当您将指针传递给该对象时,您将获得指针的副本(它指向堆上的同一个对象。)

【讨论】:

那么C++呢?似乎 C++ 可以通过执行“list a;”在堆栈上分配一个列表。然后它可以执行任何需要的操作。 @user2640480 这只会将第一个/根对象放在堆栈上,其余节点必须在堆上。 @user264080 作为一般规则,如果您在堆栈上分配对象,当您调用引用它的函数时,您将获得该对象的副本,但如果您在堆上分配它,当您将指针传递给对象时,您将获得指针的副本(它指向堆上的同一个对象。) 这样,即使在 C++ 中,我想我也无法将对象(分配在堆栈上)作为函数返回,因为它会随堆栈一起弹出。对吗? 在“栈”上完成分配时,这是指 JVM 栈,还是指用于 C/C++ 本地的 C/C++ 栈?【参考方案2】:

理论上,JVM 实现可以使用“逃逸分析”在堆栈上分配对象。如果可以确定对已创建对象的引用永远不会从堆栈中泄漏,则 JVM 可以将其分配在堆栈上而不是堆上。这样做的好处是减少垃圾收集开销;当堆栈帧退出时,可以立即回收该内存。由于参考的局部性,它也可能会提高速度。

从 Java 7 开始,在 Oracle 的 HotSpot Java 运行时中引入了逃逸分析。有了这个增强,HotSpot 可以选择不分配未修改的堆栈本地对象;它不是在堆栈上分配它们,而是完全删除分配。虽然这没有堆栈分配,但它确实证明了这样的事情是允许的运行时优化。

但是,Java 程序员无法直接控制这种行为。这是由 JIT 编译器执行的优化。我不确定语言规范是否允许在编译时进行这种优化。可能有,但我没研究过。

【讨论】:

据我所知EscapeAnalysis出现在Java 6 17版。有detailed investigation of condition

以上是关于Java可以在堆栈上分配列表吗?的主要内容,如果未能解决你的问题,请参考以下文章

如何确定 Rust 中的 new() 何时在堆栈或堆上分配

堆栈内存有限制吗?

C ++如何在堆栈上动态分配内存?

结构总是堆栈分配还是有时堆分配?

结构总是堆栈分配还是有时堆分配?

巨大的内存分配:堆栈与堆