使用java 1.6和Windows 7操作系统执行深度递归时出现java.lang.StackOverflowerError

使用java 1.6和Windows 7操作系统执行深度递归时出现java.lang.StackOverflowerError,java,memory-management,stack-overflow,Java,Memory Management,Stack Overflow,我有一个程序,在执行时会运行到一个非常深的递归中。在这个过程中,我得到了java.lang.StackOverflowerError,我的应用程序冻结了。我正在使用JDK1.6和Windows7操作系统 奇怪的是,在使用Java 1.5和Windows XP运行我的应用程序时,我没有用相同的代码库获得这个StackOverflowerError。我知道默认堆栈大小因平台和操作系统而异。但在Java1.5和WindowsXP中,我使用-Xss命令将堆栈大小设置为256k,但没有得到这个错误。在Wi

我有一个程序,在执行时会运行到一个非常深的递归中。在这个过程中,我得到了
java.lang.StackOverflowerError
,我的应用程序冻结了。我正在使用JDK1.6和Windows7操作系统

奇怪的是,在使用Java 1.5和Windows XP运行我的应用程序时,我没有用相同的代码库获得这个
StackOverflowerError
。我知道默认堆栈大小因平台和操作系统而异。但在Java1.5和WindowsXP中,我使用
-Xss
命令将堆栈大小设置为256k,但没有得到这个错误。在Windows7OS和Java1.6中使用相同的256k时,我遇到了这个错误

堆栈大小为256k,我的应用程序在Windows XP中运行时没有任何问题,并且在Windows 7操作系统中抛出
stackoverflower错误


因此,请给出从Windows 7操作系统到Windows XP线程堆栈大小的差异信息???

我认为答案是,JDK 1.5忽略将默认堆栈大小设置为特定值。比方说,如果您有一个默认的堆栈大小512K,并且(您相信)您将它设置为256K,那么最后它的值仍然是512K。使用jdk6时,您还可以将默认大小设置为256K,但在这里它确实会有这个值。这可能就是为什么您的Windows 7(更早)出现错误的原因


查看此-Xss默认值表:

Platform         Default
----------------------------------
Windows IA32     64 KB
Linux IA32       128 KB
Windows x86_64   128 KB
Linux x86_64     256 KB
Windows IA64     320 KB
Linux IA64       1024 KB (1 MB)
Solaris Sparc    512 KB 
在这里您可以看到,默认值与您运行的平台不同

见:

此外,由于在一个系统上得到的是
stackoverflowerrror
,而在另一个系统上没有,因此32位VM将使用4字节内存存储地址。64位虚拟机将以8字节存储相同的数据!因此,假设您将堆栈大小值设置为256K(是的,它是KB),32位系统(可能是您的XP系统)可以在其堆栈内存中存储65536个地址。64位系统(Windows 7系统)只能存储32768个地址。这可能是这两个系统之间的问题

通常,Java对象在32位虚拟机中消耗的内存大小与在64位虚拟机中消耗的内存大小相同。显然,如果您有一个
对象
,它引用了100个其他
对象
s,那么在64位JVM上,它会将主
对象
的大小增加400字节

此外,据说:

请注意,在某些版本的Windows上,操作系统可能会对线程进行取整 堆栈大小使用非常粗的粒度。如果请求的大小为 小于默认大小1K或更大,堆栈大小向上舍入 违约;否则,堆栈大小将向上舍入为倍数 1兆字节

64k是每个线程允许的最小堆栈空间量

见:

不幸的是,我没有找到任何具体的解释,即粗粒度是如何表达的

尝试在两个平台上运行以下示例程序,以猜测堆栈大小之间的差异:

public class StackOverflowTest {
    public static void main(String[] args) {
        recurse(0);
    }

    private static void recurse(int i) {
        try {
            recurse(++i);
        } catch (StackOverflowError e) {
            System.out.println(i);
            System.exit(0);
        }
    }
}
我的机器上的结果是:

Windows 7 (64-bit)

Stack calls     Java           Stack size
------------------------------------------
11424           JDK 5 64-bit   default
11424           JDK 5 64-bit   -Xss256K
11424           JDK 5 64-bit   -Xss1024K
6260            JRE 6 32-bit   default
4894            JRE 6 32-bit   -Xss256K
35405           JRE 6 32-bit   -Xss1024K
10448 to 10468  JDK 7 64-bit   default
2255 to 2274    JDK 7 64-bit   -Xss256K
10448 to 10468  JDK 7 64-bit   -Xss1024K
10396 to 41894  JDK 8 64-bit   default
2203 to 4590    JDK 8 64-bit   -Xss256K
10396 to 41894  JDK 8 64-bit   -Xss1024K
如果列表可以从您正在运行的其他系统扩展,那就太好了!

正如您所看到的,堆栈大小完全是个谜。事实上,不同的Java版本在堆栈内存中消耗不同的空间

此外,如果您使用
-Xss
设置堆栈大小,则在Java 5版本中将忽略该值

对于JDK 7,您不会总是得到与其他版本相同的结果。JDK 8也是如此,其范围相差很大

也许你可以自己弄清楚,如果它只是在你自己的系统上有轻微的不同或者没有

进一步阅读:

此规范允许Java虚拟机堆栈为 一个固定的大小或大小,可以根据 计算。如果Java虚拟机堆栈的大小固定, 可以选择每个Java虚拟机堆栈的大小 在创建堆栈时独立运行

所以,问题是,什么是动态扩展

然后,我在源代码中发现了一个bug,如果您运行的是早期的Java 6版本,则可能会对此感兴趣:


你能分享你的代码吗?嗨。这不是复制品,我的朋友。我的问题是,我的应用程序在WInodws Xp中运行时没有任何问题,堆栈大小为256k。但在Windows7中,它给了我相同堆栈大小256k的堆栈溢出错误。在Windows7中通过-Xss增加堆栈大小可以解决这个问题。但奇怪的是,为什么它不能在Windows7中以相同的堆栈大小工作?有人知道什么是256k单元吗?字节还是帧?这可能会有所不同,因为这样一来,64位系统上的帧可能会因为指针大小更大而更大。因此,假设单位为byte.Hi,256kB中可以容纳更少的帧。谢谢你的回复。现在很清楚,默认堆栈大小将因平台而异。但若我们在WindowsXP和Windows7中设置相同的堆栈大小,那个么应用程序在WindowsXP中运行成功,而在Windows7中运行失败。有什么理由吗。非常感谢您对此的回复。提前谢谢。我猜你的Windows7系统是64位版本,XP是32位版本。因此,这可能会改变内存的使用方式!我已经扩展了我的答案来区分32位和64位系统。您对32位和64位版本之间差异的解释对我来说是有意义的,可能是事实。但是,我在Windows XP和Windows 7上都使用32位版本。在这种情况下,内存消耗会产生任何影响??我已经更改了答案,并添加了一个示例程序,您可以尝试在这两种平台上执行。也许,你能想出办法!事实上,你的问题很好;)