我在“stackoverflow”网站中询问有关“java堆栈溢出”的问题:)
对特定输入进行一些递归函数调用的特定线程在 Oracle Java 7(64 位) 中运行良好,配置的堆栈大小为 228k (-Xss228k)。
但是,在 Oracle Java 8(64 位) 中,针对同一输入运行相同递归代码的同一线程会针对同一堆栈抛出 java.lang.StackOverflowError大小为228k。如果堆栈大小增加到 512k (-Xss512k),它在 Java 8 中运行良好。
知道为什么会发生这种情况吗?与 Java 7 相比,Java 8(Hotspot JVM)是否进行了任何更改,这些更改可能会增加递归函数调用的堆栈内存消耗?如果需要,我可以提供更多详细信息。
(编辑)注意:对于 228k 的堆栈大小,相同的递归深度在 Java 7 中“始终”有效,但在 Java 8 中“始终”失败。
最佳答案
我写了a small test针对不同的递归场景(静态或实例方法,不同数量的int参数)。以下是使用 -Xss228k
选项在不同版本的 HotSpot JVM 64 位上的结果(发生 StackOverflowError
之前的调用次数)。请注意,运行之间的数字有所不同(我对每个 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
很期望 Instance/0
与 Static/1
相同,依此类推,因为实例调用需要将 this
作为附加参数。
因此,JDK 7 和 JDK 8 之间允许的递归调用数量确实有所下降(Static/0
情况除外):您会丢失大约 30-40 次调用(大约占总数的 5%)数数。因此,在您的应用程序中,您可能非常接近极限。顺便说一句,我注意到 -Xss256k
和 -Xss260k
之间突然跳转(在 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
因此,您可以尝试将堆栈大小增加到 -Xss260k
,它应该足以满足您的任务。
顺便说一句,32 位 JVM 允许使用相同的 -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
因此,您也有可能从 32 位 Java-7 切换到 64 位 Java-8。在这种情况下,当然需要更多的堆栈空间,因为即使使用压缩的 OOP,堆栈中的指针似乎也是 64 位,因此占用了更多的空间。
关于memory - 与 Java 7 相比,运行相同递归代码的相同线程在 Java 8 中似乎消耗更多的堆栈内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32521271/