在Java中如何在栈内存中创建对象?

20

这只是一个出于好奇心的简单理论问题。我一直都像个Java迷。但有一件事让我想知道为什么Java不提供在堆栈上创建对象的机制?如果我可以像在C#中创建结构体一样,在堆栈上创建小的Point(int x,int y)对象,不是更有效率吗?Java是否因为特殊的安全原因而限制了这种功能呢? :)


1
当你将它放入一个不在栈上的容器中时会发生什么?当你返回时,该容器现在具有对未分配内存的引用。 - Max
1
@Max:大概需要包括一些结构,让编译器能够对此进行检查。 - Thilo
@Max:容器没有对原始对象的引用,它只有一个副本或装箱后的副本。.NET/C#已经拥有这个功能15年了。https://msdn.microsoft.com/zh-cn/library/yz2be5wk.aspx - csauve
3个回答

19

这里的策略是,Java不会将这个决定泄漏到语言中,而是让JVM/Hotspot/JIT/runtime决定在哪里以及如何分配内存。

有研究正在进行以使用“逃逸分析”来找出哪些对象实际上不需要进入堆并将它们分配到栈上。我不确定这是否已经被纳入主流的JVM中。但如果这样做了,它将由运行时控制(像-XX:something这样的东西),而不是由开发人员控制。

这样做的好处是即使旧代码也可以从这些未来的增强中受益,而不必更新代码本身。

如果您喜欢手动管理(但仍然希望编译器检查它是否“安全”),那么可以看看Rust。


6
从6u23版本开始,可以启用Java SE 7中介绍的性能增强功能。 - jtahlborn
2
@jtahlborn:+1。我认为当前的优化措施并没有像在堆栈上分配对象那样远,不过从发布说明来看,它似乎是消除锁定和冗余复制现有对象。 - Thilo
从jtahlborn发布的链接中得到一个+1:“它不会将非全局逃逸对象的堆分配替换为栈分配。” 这意味着ArgEscapeNoEscape将在堆栈上分配。 但是,它并没有被明确提到... - Nir Alfasi
@alfasin:是的,不太清晰。我把它理解为“用没有任何分配的冗余防御性副本替换堆分配”(重复使用现有对象),这似乎是他们给出的示例中所发生的事情。 - Thilo
我如何确保我的对象通过堆栈传递?应用了哪些规则? - Sergey Ponomarev

6

这个功能暂时会被引入到Java中,目前还没有确切的发布时间,所以你只能希望它会在Java 10中出现。

这项提议被称为“Value Types”,您可以在“Valhalla项目”的邮件列表中关注它。

我不知道它最初为什么没有出现在语言中,可能最初认为它是不必要的,或者根本没有时间来实现它。


好的!Java将“暂时”赶上C#?“某个时候”(商标) - csauve
@skiwi,您能否简要解释一下什么是值类型? - Quazi Irfan

3

一个常见的问题是使用在堆栈上创建的对象来初始化一些全局引用。当创建该对象的方法退出时,你要指向什么?

尽管如此,在Java中也可以使用堆栈创建对象,只是使用了逃逸分析(Escape Analysis)来确保不会发生上述情况。


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