For those who can't reproduce this fluctuation. Find the layer value starting from which method will reliably throw StackOverflowError. The closer this value to the real threshold the better. Now call this method from inside the loop (on my machine maxLayer = 11500):
int i = 11500;
while (true) {
System.out.println(i);
triangleFract(i++);
}
It will throw StackOverflowError. Now decrease this value a little bit (looks like 5-10% should be enough):
int i = 10500;
while (true) {
System.out.println(i);
triangleFract(i++);
}
Well on my machine this doesn't throw any error and successfully jumps over 11500. Actually it works fine up until 16000.
So whatever it is it probably involves JVM optimisations. I tried to run a program with -XX:+PrintCompilation. I saw how JIT does its job while looping:
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)
May it be compilation?
Let's try to delay compilation so it affects us as late as possible. I tried to play with -XX:CompileThreshold flag and pretty soon found a value (-XX:CompileThreshold=1000000) which doesn't let my loop jump over 11500.
UPDATE
I finally reproduced it without any tweaking of compilation threshold. For me it looks like it only happens when I run program in my IDE (IntelliJ IDEA). So it may have something to do with IDEA's 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 it usually prints out something less than 100 (95-98). Which is consistent to what I saw when did it manually. When I skip the launcher:
for I in `seq 1 100`; do
java \
Triangle 2>&1| grep Stack; done | wc -l
it always prints out 100.
triangleFract(7000)multiple times without anyStackOverflowError. - arshajiilongs (starting at aboutlayer = 41). - arshajii