与Java 7相比,运行相同递归代码的相同线程似乎在Java 8中消耗更多堆栈内存 [英] Same thread running the same recursive code seems to consume more stack memory in Java 8 compared to Java 7
问题描述
我在stackoverflow网站上问一个关于java堆栈溢出的问题:)
I am asking a question about "java stack overflow" in the "stackoverflow" site :)
一个特定的线程,它为特定的输入做一些递归函数调用在 Oracle Java 7(64位)中运行良好,配置的堆栈大小为228k(-Xss228k)。
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).
但是,运行相同输入的相同递归代码的同一个线程会在 Oracle Java 8中抛出 java.lang.StackOverflowError (64位)对于相同的堆栈大小228k。如果堆栈大小增加到512k(-Xss512k),它在Java 8中运行良好。
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).
任何想法为什么会发生这种情况?与Java 7相比,Java 8(Hotspot JVM)是否进行了任何更改,这可能会增加递归函数调用的堆栈内存消耗?如果需要,我可以提供更多细节。
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.
(编辑)注意:相同的递归深度在Java 7中始终起作用,但在Java 8中对于堆栈大小始终失败228k。
(Edit) NOTE: The same recursion depth works "always" in Java 7 but fails "always" in Java 8 for a stack size of 228k.
推荐答案
我写了一个小测试,用于不同的递归场景(静态或实例方法,不同数量的int参数)。这是在不同版本的HotSpot JVM 64bit上使用 -Xss228k
选项的结果(在 StackOverflowError
之前调用的次数)。请注意,运行之间的数字有所不同(我在每个JVM上启动两次):
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
非常期待 Instance / 0
与 Static / 1
相同,等等,因为实例调用需要传递这个
作为一个额外的参数。
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.
所以确实允许递归调用数量有所下降(除了静态/ 0
case)在JDK 7和JDK 8之间:你输掉了大约30-40个电话(大约5%)。所以可能在您的应用程序中,您非常接近极限。顺便说一下,我注意到 -Xss256k
和 -Xss260k
之间突然跳转(在1.8.0_40测试):
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
所以你可以尝试将堆栈大小增加到 -Xss260k
,这对你的任务应该足够了。
So you may try to increase stack size to -Xss260k
and it should be enough for your task.
顺便说一下,32位JVM允许使用相同的 -Xss228k
进行更多的调用:
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
因此,您也可能已从32位Java-7切换到64位Java-8。在这种情况下,当然需要更多的堆栈空间,因为即使堆栈中的压缩OOP指针似乎是64位,因此占用更多空间。
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.
这篇关于与Java 7相比,运行相同递归代码的相同线程似乎在Java 8中消耗更多堆栈内存的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!