Same thread running the same recursive code seems

2020-03-26 12:52发布

问题:

I am asking a question about "java stack overflow" in the "stackoverflow" site :)

A particular thread which makes some recursive function calls for a particular input runs fine in Oracle Java 7 (64 bit) for a configured stack size of 228k (-Xss228k).

However, the same thread running the same recursive code for the same input throws a java.lang.StackOverflowError in Oracle Java 8 (64 bit) for the same stack size of 228k. It runs fine in Java 8 if the stack size is increased to 512k (-Xss512k).

Any idea why this could happen? Have any changes been made in Java 8 (Hotspot JVM) compared to Java 7 which could increase the stack memory consumption for recursive function calls? I can provide additional details if required.

(Edit) NOTE: The same recursion depth works "always" in Java 7 but fails "always" in Java 8 for a stack size of 228k.

回答1:

I wrote a small test for different recursion scenarios (static or instance method, different number of int parameters). Here's the results (number of calls before StackOverflowError occurs) on different versions of HotSpot JVM 64bit with -Xss228k option. Note that numbers differ somewhat between runs (I launched twice with every JVM):

          St/0  St/1  St/2  St/3  St/4  In/0  In/1  In/2  In/3  In/4
1.7.0_60  2720  2519  2309  2131  1979  2519  2309  2131  1979  1847
1.7.0_60  2716  2516  2306  2128  1976  2516  2306  2128  1976  1845
1.7.0_79  2716  2516  2306  2128  1976  2516  2306  2128  1976  1845
1.7.0_79  2729  2528  2317  2139  1986  2528  2317  2139  1986  1853
1.7.0_80  2718  2518  2308  2130  1978  2518  2308  2130  1978  1846
1.7.0_80  2738  2536  2324  2146  1992  2536  2324  2146  1992  1859
____________________________________________________________________
1.8.0_25  2818  2469  2263  2089  1940  2469  2263  2089  1940  1810
1.8.0_25  3279  2468  2262  2088  1939  2468  2262  2088  1939  1810
1.8.0_40  2714  2467  2262  2088  1938  2467  2262  2088  1938  1809
1.8.0_40  2735  2486  2279  2104  1953  2486  2279  2104  1953  1823
1.8.0_60  2729  2481  2274  2099  1949  2481  2274  2099  1949  1819
1.8.0_60  2719  2472  2266  2091  1942  2472  2266  2091  1942  1812
____________________________________________________________________
1.9_b80   2717  2470  2264  2090  1941  2470  2264  2090  1941  1811
1.9_b80   2715  2468  2263  2088  1939  2468  2263  2088  1939  1810

It's quite expected that Instance/0 is the same as Static/1 and so on as instance call need to pass this as an additional argument.

So indeed there's some degradation of number of recursive calls allowed (except for Static/0 case) betwee JDK 7 and JDK 8: you lose around 30-40 calls (roughly 5%) of total count. So probably in your application you was very close to the limit. By the way I noticed a sudden jump between -Xss256k and -Xss260k (tested on 1.8.0_40):

          St/0  St/1  St/2  St/3  St/4  In/0  In/1  In/2  In/3  In/4
-Xss256k  2724  2476  2270  2095  1945  2476  2270  2095  1945  1816
-Xss260k  4493  3228  2959  2731  2536  3228  2959  2731  2536  2367

So you may try to increase stack size to -Xss260k and it should be enough for your task.

By the way 32-bit JVM allows much more calls with the same -Xss228k:

          St/0  St/1  St/2  St/3  St/4  In/0  In/1  In/2  In/3  In/4
7u67_32b  7088  5078  4655  4297  3990  5078  4655  4297  3990  3724
7u67_32b  6837  5092  4667  4308  4001  5092  4667  4308  4001  3734

Thus it's also possible that you've switched from 32-bit Java-7 to 64-bit Java-8. In this case, of course much more stack space is needed as even with compressed OOPs pointers in the stack seem to be 64bit, thus occupying more space.