Background
I ran the code (located at the bottom) to measure the performance of an explicit downgrade of Java, and I came across what seems to me to be a bit of an anomaly ... or maybe two anomalies.
I already reviewed this thread in Java, but it seems that it was only about casting in general, and not about this specific phenomenon. This thread covered similar topics, and I don't need advice on premature optimization - I tune parts of my application for maximum performance, so this is a logical step.
Tests
Basically, I wanted to test downcasting performance compared to the method .toString()for objects that were Strings but were printed as Objects. So, I created String aand Object bwith equivalent contents, performed three cycles and timed them.
- Loop 1 -
((String) b).toLowerCase(); - Loop 2 -
b.toString().toLowerCase(); - and cycle 3 -
a.toLowerCase().
Test results
(Measurements in milliseconds.)
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
-----------|--------------|----------|----------|----------
Code used for tests
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);
Finally the question
What I find most fascinating is that cycle 2 ( .toString()) seemed to perform the best of the three (especially in test B), which does not create an intuitive meaning. Why would a call .toString()be faster than already having an object 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 ******/