Eri*_*ric 5 java performance casting
我一直在运行一个代码(在底部发布)来衡量显式Java向下转换的性能,而且我遇到了我觉得有点像异常......或者两个异常.
我已经看过这个关于Java构建开销的线程,但它似乎只讨论了一般的转换,而不是这个特殊的现象.这个主题涵盖了类似的主题,我并不需要过早优化的建议 - 我正在调整应用程序的一部分以获得最佳性能,因此这是合乎逻辑的步骤.
我基本上想测试向下转换的性能与s .toString()对象的方法String,但是输入为Objects.所以,我创建了一个String a和一个Object b具有相同内容,运行三个循环,并计时.
((String) b).toLowerCase();b.toString().toLowerCase();a.toLowerCase().(以毫秒为单位的测量值.)
iters | Test Round | Loop 1 | Loop 2 | Loop 3
-----------|--------------|----------|----------|----------
50,000,000 | 1 | 3367 | 3166 | 3186
Test A | 2 | 3543 | 3158 | 3156
| 3 | 3365 | 3155 | 3169
-----------|--------------|----------|----------|----------
5,000,000 | 1 | 373 | 348 | 369
Test B | 2 | 373 | 348 | 370
| 3 | 399 | 334 | 371
-----------|--------------|----------|----------|----------
500,000 | 1 | 66 | 36 | 33
Test C | 2 | 71 | 36 | 41
| 3 | 66 | 35 | 34
-----------|--------------|----------|----------|----------
50,000 | 1 | 27 | 5 | 5
Test D | 2 | 27 | 6 | 5
| 3 | 26 | 5 | 5
-----------|--------------|----------|----------|----------
Run Code Online (Sandbox Code Playgroud)
long t, iters = ...;
String a = "String", c;
Object b = "String";
t = System.currentTimeMillis();
for (int i = 0; i < iters; i++) {
c = ((String) b).toLowerCase();
}
System.out.println(System.currentTimeMillis() - t);
t = System.currentTimeMillis();
for (int i = 0; i < iters; i++) {
c = b.toString().toLowerCase();
}
System.out.println(System.currentTimeMillis() - t);
t = System.currentTimeMillis();
for (int i = 0; i < iters; i++) {
c = a.toLowerCase();
}
System.out.println(System.currentTimeMillis() - t);
Run Code Online (Sandbox Code Playgroud)
我发现最令人着迷的是循环2(.toString())似乎表现出三者中最好的(特别是在测试B中) - 这没有直观意义.为什么呼叫.toString()比已经拥有一个String对象更快?
困扰我的另一件事是它不能扩展.如果我们比较测试A和D,当它们相互比较时它们会偏离9倍(27*1000 = 27000,而不是3000); 为什么迭代次数会出现这种巨大的差异?
任何人都可以解释为什么这两个异常被证明是真的吗?
更新:根据Bruno Reis的解决方案的建议,我使用一些编译器输出再次运行我的基准测试.第一个循环塞满了初始化的东西,所以我放入一个"垃圾"循环来做到这一点.一旦完成,结果更接近预期.
这是控制台的完整输出,使用5,000,000次迭代(由我评论):
50 1 java.lang.String::toLowerCase (472 bytes)
50 2 java.lang.CharacterData::of (120 bytes)
53 3 java.lang.CharacterDataLatin1::getProperties (11 bytes)
53 4 java.lang.Character::toLowerCase (9 bytes)
54 5 java.lang.CharacterDataLatin1::toLowerCase (39 bytes)
67 6 n java.lang.System::arraycopy (0 bytes) (static)
68 7 java.lang.Math::min (11 bytes)
68 8 java.util.Arrays::copyOfRange (63 bytes)
69 9 java.lang.String::toLowerCase (8 bytes)
69 10 java.util.Locale::getDefault (13 bytes)
70 1 % Main::main @ 14 (175 bytes)
[GC 49088K->360K(188032K), 0.0007670 secs]
[GC 49448K->360K(188032K), 0.0024814 secs]
[GC 49448K->328K(188032K), 0.0005422 secs]
[GC 49416K->328K(237120K), 0.0007519 secs]
[GC 98504K->352K(237120K), 0.0122388 secs]
[GC 98528K->352K(327552K), 0.0005734 secs]
595 1 % Main::main @ -2 (175 bytes) made not entrant
548 /****** Junk Loop ******/
597 2 % Main::main @ 61 (175 bytes)
[GC 196704K->356K(327552K), 0.0008460 secs]
[GC 196708K->388K(523968K), 0.0005100 secs]
343 /****** Loop 1 ******/
939 2 % Main::main @ -2 (175 bytes) made not entrant
940 11 java.lang.String::toString (2 bytes)
940 3 % Main::main @ 103 (175 bytes)
[GC 393092K->356K(523968K), 0.0036496 secs]
377 /****** Loop 2 ******/
1316 3 % Main::main @ -2 (175 bytes) made not entrant
1317 4 % Main::main @ 145 (175 bytes)
[GC 393060K->332K(759680K), 0.0008326 secs]
320 /****** Loop 3 ******/
Run Code Online (Sandbox Code Playgroud)
基准测试存在缺陷,因为SO和其他地方的大多数问题都与Java代码基准测试有关.您测量的内容远远超出您的想象,例如JIT编译方法,HotSpot优化循环等.
请访问http://www.ibm.com/developerworks/java/library/j-jtp02225/index.html.
此外,服务器VM和客户端VM的行为也不同(JVM在客户端启动速度更快,但运行速度慢一段时间,因为它在编译时开始解释字节码,而服务器VM在运行之前编译它)等.
GC可能也会产生干扰,如果您在基准测试期间获得任何Full GC(通常是Full GCs完全暂停其他所有线程),则更是如此.即使是次要的集合也可能会产生一些影响,因为它们可以使用相当多的CPU来清理循环中可能存在的巨大混乱.
要做一个适当的基准测试,你应该"预热"JVM,打开JVM的大量输出,以确定你正在测量的内容等.
在这里查看这个问题,它解决了如何用Java编写基准测试,包括我上面提到的主题以及更详细的内容:如何在Java中编写正确的微基准测试?
| 归档时间: |
|
| 查看次数: |
240 次 |
| 最近记录: |