Java JVM是否重用自定义类的相同不可变实例,就像它与String一样?



如果您创建字符串"codecodecode"在现实中,它只存在一次。,因为JVM是这样优化的。

但是这个类呢:

final public class ImmutReuseTest {
final public int num;
final public SomeImmutableThing thing;
public ImmutReuseTest(final int num, final SomeImmutableThing thing) {
this.num = num;
this.thing = thing;
}
}
final public class SomeImmutableThing {
final public int nomm;
final public String text;
public SomeImmutableThing(final int nomm, final String text) {
this.nomm = nomm;
this.text = text;
}
}
  1. 如果我创建数千个ImmutReuseTest实例,其中一些将具有100%等于值,JVM会像对String那样优化这些相等的值吗?("Equal"含义:实例之间的单个字段是相等的,这是关于类型为"someimmutablething"的字段。意思是:那些thing字段在那些thing实例之间也是相等的。)

  2. 如果实例具有完全相同的怎么办?价值观?("Identical"含义:SomeImmutableThing实例是相同的,而不仅仅是相等)

  3. 如果我们改变SomeImmutableThing来使用一个被认为是不可变的类,但有内部可变值(像String一样,但String是一个糟糕的例子,因为专门的JVM优化)?例如,让我们使用一个具有公共可变字段但"有效的final"。或者只有"有效终结"的私有可变字段。

执行环境必须保留Java编程语言的语义,即new操作符的语义:

类实例创建表达式的值是对指定类的新创建对象的引用。每次对表达式求值时,都会创建一个新的对象。

这并不依赖于你的类的可变性,只要Java没有提供除了new之外的其他方法来实例化你的类,就不会有实例共享,除非你自己实现了它。

您将(或可能)最终使用重用对象的已知情况不涉及new,例如

String s = "foo";
Integer i = 42;
Runnable r = () -> System.out.println("hello");

此外,对于有意未指定对象标识的类型,如基于值的类,实例总是通过工厂方法获得,因此它们实际实例化的方式对应用程序是不可见的。

对于真值类型,正如计划在未来的Java版本中添加的那样,我们需要一个用于创建/获取实例的新语法结构或关于new操作符的语言规范更改。

JVM仍然可以做任何优化,只要它不改变程序逻辑,所以如果它可以证明应用程序从未对某些对象执行身份敏感的操作,或者可以假装这些操作仍然具有相同的效果(例如new Foo() == new Foo()可以被false取代),它可以将相同的对象合并为一个。这显然很难或几乎不可能证明。

目前,当整个生命周期在优化器的范围内时,可以对短生命周期对象执行此操作。然而,在这些情况下,JVM将完全消除分配,而不是搜索相同的对象进行重用。参见HotSpot Wiki/Escape Analysis…

如果我创建了数千个ImmutReuseTest实例,其中一些实例将具有100%相等的值,JVM会像字符串一样优化这些相等的实例吗?

答案是否定的。将类编写为不可变的不会影响JVM管理其实例的方式。Java的值类型,作为Valhalla项目的一部分,旨在解决这个问题。String优化是一个特例。

如果实例具有完全相同的值怎么办?("Identical"含义:SomeImmutableThing实例是相同的,而不仅仅是相等)

是,在这种情况下,只有一个实例具有该标识。

我不太明白你最后一个问题,但它似乎和第一个没有什么不同。

相关内容

  • 没有找到相关文章

最新更新