Java 为什么字符串的创建时间不同?

Java 为什么字符串的创建时间不同?,java,Java,谁能给我解释一下这里发生了什么 情景1 这: 比这花费的时间要少: 为什么在场景1中调用空字符串()构造函数会花费更多的时间,而在场景2中却没有?我查看了String()和String(String-original)的文档,但没有看到任何优化。这种优化(如果它确实是优化)是在其他地方进行的吗 更新: 我是如何安排时间的: 我的系统: Windows 7 x64,使用Java 7和Eclipse,JVM可以进行运行时优化。在许多/大多数情况下,您只会在迭代次数较多的地方注意到它们。在场景1中,很

谁能给我解释一下这里发生了什么

情景1

这:

比这花费的时间要少:

为什么在场景1中调用空字符串()构造函数会花费更多的时间,而在场景2中却没有?我查看了String()和String(String-original)的文档,但没有看到任何优化。这种优化(如果它确实是优化)是在其他地方进行的吗

更新:

我是如何安排时间的:

我的系统:


Windows 7 x64,使用Java 7和Eclipse,JVM可以进行运行时优化。在许多/大多数情况下,您只会在迭代次数较多的地方注意到它们。在场景1中,很可能一个优化的方式与另一个不同


尝试在禁用运行时优化的情况下运行,您仍然会得到相互冲突的结果。

如果不知道您的基准测试结果会如何,很难说,但我会把钱花在
系统上。nanoTime
没有足够高的分辨率来支持它。我敢打赌
String()
String(“”
只需
nanoTime
时钟的不到一个滴答声即可实例化,并且您的结果是一个事实的产物,即您正试图测量小于其分辨率的东西

(三年前)问题指向一个实例约20纳秒,而我之前链接的问题表明,
nanoTime
的分辨率实际上约为10纳秒。我的猜测是,您的实例化时间实际上在10 ns到20 ns之间,两者之间的差别只是噪音

根据评论进行编辑:

有点不对劲。单个对象实例化不可能需要3000 ns。我猜您正在测量JVM预热时间或类似时间,可能是
的存在导致JVM遇到了一些没有
的情况下不会遇到的代码路径。我不确定是什么导致了您的问题,但我不认为您正在测量的是对象实例化时间。

好的,我将此作为一个新的答案提交,因为它确实与我的另一个答案不同,并且评论中没有足够的空间

您所看到的是System.nanoTime缺乏准确性,如下所述:

在运行相同测试的多次迭代(适当预热)后,我(为我的机器)确定了以下内容

  • new String()的运行时间介于3.7到10.4ns之间,平均约为4.1 ns
  • 新字符串(“”)的运行时间介于6.0和14.8ns之间,平均值约为6.3
  • 对new String()和new String(“”)的单个调用都返回0ns或307ns的计时,偶尔返回306ns
这基本上证明了帕特里克的答案是正确的。纳米钟的精度还不足以测量一次通话。精确值只能确定为多个调用的平均值。在我的机器上,精度似乎是~300ns


如果您能够以某种方式测量单个调用,我强烈怀疑这会表明,无论您调用它多少次,new String()与new String(“”)具有相同的差异。

您测试的Java版本是什么?您是如何计算时间的?您得到的时间是多少?使用
String str=new String(“”
),您将创建两个字符串,第一个用于静态空字符串,第二个用于
new
String str=“”
String str=new String()
public String(){this.value=new char[0];}public String(String original){this.value=original.value;this.hash=original.hash;}@Baldy No,这是完全错误的<代码>字符串str=“”与
String str=new String(“”)明显不同由于实习。我用
-Djava.compiler=NONE
禁用了JIT,得到了大致相同的结果(除了两个场景2循环都需要更长的时间)。或者我需要做些别的事情来禁用运行时优化?你也可能会遇到这样的情况,“你必须先建立一个完整的工厂,然后才能从中获得一罐bean”。与执行3000000次(仍然只有一次初始化)相比,执行一次会导致初始化占总成本的百分比更高。您可以通过让测试在代码中出现两次来尝试“预热”测试,但只能测量它运行的第二次。这样,任何初始化都将在第一个(未测量的)代码中完成。感谢您的输入,Ted。是的,实际上我也做了这个测试。场景2中的String()和String(“”)在经过几次连续初始化后最终都会下降到384ns。但是,这只能证明正在进行某些优化(或者用您的话说“工厂已经启动”)。此外,它还提出了一个新问题——为什么在场景1中不进行这种优化?这可能是Patrick在他的帖子“JVM预热”中提到的现象。所以,假设你是对的,我从场景1得到的结果是正确的,因为它打破了纳米时间分辨率的时间框架?然而,我的基准测试总是相同的(例如,String()大约5000纳秒,String(“”)大约3000纳秒。场景1应该可以,因为它不会试图在小于
nanoTime
分辨率的时间单位内工作。我不知道为什么
String()
的性能会不同于
String(“”)
,但我正试图解释场景1和场景2之间的区别。什么度量给了您5000和3000纳秒?对于场景2,String()和String(“”),当连续多次运行时,最终都会下降到384纳秒。这可能与您提到的“JVM预热”有关。但它提出了一个新问题-为什么会这样“优化”/“预热”在场景1中不可见?编译器内部不可见
// around 50ms
for (int i = 0; i < 3000000; i++) {
    String str = new String();
}
// around 25ms
for (int i = 0; i < 3000000; i++) {
    String str = new String("");
}
String str = new String(); // around 3000ns
String str = new String(""); // around 5000ns
long start = System.nanoTime();
//doing stuff here
long elapsedTime = System.nanoTime() - start;