memory - 与 Java 7 相比,运行相同递归代码的相同线程在 Java 8 中似乎消耗更多的堆栈内存

标签 memory recursion java-8 stack-overflow jvm-hotspot

我在“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/0Static/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/

相关文章:

java - 即使使用close关闭spring上下文,为数据库连接创建的TimerThreads仍继续运行

java - 如何处理 Iterable.forEach 中的 IOException?

python - 变量赋值存储在内存中的什么位置?

c - 为什么我在不使用 malloc() 分配后不必使用 free()

sql - 如何在递归表(SQL)中获取 2 行的最低公共(public)父级

java - 如何使静态递归方法返回 HashMap?

java:构建三叉树并且我的节点不会被删除

c - 从内存中读取 "zero"是否比读取其他值更快?

python - 检测到一个方法是递归的而不调用它?

Java 8 DateTimeFormatter 无法解析 "Etc/GMT"时区