For those who cannot reproduce this fluctuation. Find the layer value from which the method will throw StackOverflowError reliably. The closer this value is to the real threshold, the better. Now call this method from the loop (on my machine maxLayer = 11500 ):
int i = 11500; while (true) { System.out.println(i); triangleFract(i++); }
It will throw a StackOverflowError . Now slightly decrease this value (it seems like 5-10% should be enough):
int i = 10500; while (true) { System.out.println(i); triangleFract(i++); }
Well, on my machine this does not cause any error and successfully jumps over 11500 . In fact, it works fine up to 16000 .
So, whatever that is, it is probably related to JVM optimization. I tried to run the program using -XX:+PrintCompilation . I saw how JIT does its work during the loop:
117 1 java.lang.String::hashCode (64 bytes) 183 2 java.lang.String::charAt (33 bytes) 189 3 sun.nio.cs.UTF_8$Decoder::decodeArrayLoop (553 bytes) 201 4 java.math.BigInteger::mulAdd (81 bytes) 205 5 java.math.BigInteger::multiplyToLen (219 bytes) 211 6 java.math.BigInteger::addOne (77 bytes) 215 7 java.math.BigInteger::squareToLen (172 bytes) 219 8 java.math.BigInteger::primitiveLeftShift (79 bytes) 224 9 java.math.BigInteger::montReduce (99 bytes) 244 10 sun.security.provider.SHA::implCompress (491 bytes) 280 11 sun.nio.cs.UTF_8$Encoder::encodeArrayLoop (490 bytes) 282 12 java.lang.String::equals (88 bytes) 11400 289 13 java.lang.String::indexOf (151 bytes) 293 14 java.io.UnixFileSystem::normalize (75 bytes) 298 15 java.lang.Object::<init> (1 bytes) 298 16 java.util.jar.Manifest$FastInputStream::readLine (167 bytes) 299 17 java.lang.CharacterDataLatin1::getProperties (11 bytes) 300 18 NormalState::triangleFract (74 bytes) 308 19 java.math.BigInteger::add (178 bytes) 336 20 java.lang.String::lastIndexOf (151 bytes) 337 21 java.lang.Number::<init> (5 bytes) 338 22 java.lang.Character::digit (6 bytes) 340 23 java.lang.Character::digit (168 bytes) 342 24 java.lang.CharacterDataLatin1::digit (85 bytes) 343 25 java.math.BigInteger::trustedStripLeadingZeroInts (37 bytes) 357 26 java.lang.String::substring (83 bytes) 360 27 java.lang.String::lastIndexOf (10 bytes) 360 28 java.lang.String::lastIndexOf (29 bytes) 361 29 java.math.BigInteger::<init> (24 bytes) 361 30 java.lang.Integer::parseInt (269 bytes) 361 31 java.math.BigInteger::<init> (8 bytes) 362 32 java.math.BigInteger::<init> (347 bytes) 404 33 java.math.BigInteger::multiply (72 bytes) 404 34 java.math.BigInteger::add (123 bytes)
Maybe this is a compilation? Try deferring the compilation so that it affects us as late as possible. I tried to play with the -XX:CompileThreshold and pretty soon found a value ( -XX:CompileThreshold=1000000 ) that prevents my loop from jumping over 11500 .
UPDATE
I finally played it without any compilation threshold setting. For me, it looks as if I were running the program in my IDE (IntelliJ IDEA). So this may be due to the IDEA launcher. I copied its command line and used it in a small script:
for I in `seq 1 100`; do java ... com.intellij.rt.execution.application.AppMain \ Triangle 2>&1| grep Stack; done | wc -l
And what I found out is he usually prints something less than 100 (95-98). This is consistent with what I saw when I did this manually. When I skip the launcher:
for I in `seq 1 100`; do java \ Triangle 2>&1| grep Stack; done | wc -l
he always prints 100.
user381105
source share