与Java 7相比,运行相同递归代码的相同线程似乎在Java 8中消耗更多堆栈内存 [英] Same thread running the same recursive code seems to consume more stack memory in Java 8 compared to Java 7

查看:275
本文介绍了与Java 7相比,运行相同递归代码的相同线程似乎在Java 8中消耗更多堆栈内存的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆