使用Java 1.6和Windows 7 OS进行深度递归时出现java.lang.StackOverflowError [英] java.lang.StackOverflowError while doing deep recursion with Java 1.6 and Windows 7 OS

查看:105
本文介绍了使用Java 1.6和Windows 7 OS进行深度递归时出现java.lang.StackOverflowError的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个程序在执行时会遇到非常深的递归。在这个中间,我得到 java.lang.StackOverflowError ,我的应用程序冻结了。我正在使用JDK 1.6和Windows 7操作系统。



奇怪的是,我没有得到这个 StackOverflowError 使用Java 1.5和Windows XP运行我的应用程序时的相同代码库。据我所知,默认堆栈大小因平台和操作系统而异。但是使用Java 1.5和Windows XP,我使用 -Xss 命令设置堆栈大小为256k,而不是出现此错误。在Windows 7操作系统和Java 1.6中使用相同的256k,我收到此错误。



堆栈大小为256k,我的应用程序在Windows XP中运行没有任何问题,它是在Windows 7操作系统中抛出 StackOverflowError



因此,请提供有关线程堆栈大小与Windows 7操作系统有何不同的信息吗?

解决方案

我认为答案是, JDK 1.5 忽略将默认堆栈大小设置为特定值。比方说,如果您的默认堆栈大小为512K并且(您相信)将其设置为256K,那么它仍将具有512K的值。使用 JDK 6 ,您还可以将默认大小设置为256K,但这里确实会有此值。这可能就是为什么你的Windows 7收到错误的原因(早先)!






看看这个 -Xss默认值表:

 平台默认值
---------- ------------------------
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

在这里你可以看到,默认值与你正在运行的平台不同。



参见:< a href =http://docs.oracle.com/cd/E13150_01/jrockit_jvm/jrockit/jrdocs/refman/optionX.html#wp1024112 =nofollow> http://docs.oracle.com/cd/ E13150_01 / jrockit_jvm / jrockit / jrdocs / refman / optionX.html #wp1024112



此外,因为你得到的是 StackOverflowError 在一个系统上,而不是另一个,32位虚拟机将存储地址有4个字节的内存。 64位VM将以8字节存储相同的内容!因此,假设您将堆栈大小值设置为256K(是的,它是KBytes),32位系统(可能是您的XP系统)可以在其堆栈内存中存储65,536个地址。 64位系统(Windows 7系统)只能存储32,768个地址。这可能是这两个系统之间的问题。



一般来说,Java 对象在32中消耗与64中相同的内存大小位VM。显然,如果你有一个 Object ,它引用了100个其他的 Object ,它会增加main的大小对象 64位JVM上的400字节。



另外说:


请注意,在某些版本的Windows上,操作系统可能会使用非常粗略的粒度来舍入线程
堆栈大小。如果请求的大小是
小于默认大小1K或更多,则堆栈大小向上舍入
到默认值;否则,堆栈大小向上舍入为1 MB的倍数



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


请参阅: http://www.oracle.com/technetwork/java/hotspotfaq-138619.html#threads_oom



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



尝试在两个平台上运行以下示例程序来猜测,多少堆栈大小彼此不同:

  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位)

堆栈调用Java堆栈大小
- -----------------------------------------
11424 JDK 5 64-位默认值
11424 JDK 5 64位-Xss256K
11424 JDK 5 64位-Xss1024K
6260 JRE 6 32位默认
4894 JRE 6 32位-Xss256K
35405 JRE 6 32位-Xss1024K
10448至10468 JDK 7 64位默认
2255至2274 JDK 7 64位-Xss256K
10448至10468 JDK 7 64位-Xss1024K
10396到41894 JDK 8 64位默认
2203到4590 JDK 8 64位-Xss256K
10396到41894 JDK 8 64位-Xss1024K

如果列表可以从您正在运行的其他系统扩展,那就太棒了!



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



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



使用JDK 7,你不会总是得到相同的结果在其他版本上。 JDK 8也是如此,其中范围大不相同。



也许你可以弄清楚自己,如果它在你自己的系统上只是微不足道。



进一步阅读: http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-2.html#jvms-2.5.2


此规范允许Java虚拟机堆栈固定大小为
a或动态扩展
并按照
计算。如果Java虚拟机堆栈具有固定大小,则每个Java虚拟机堆栈的大小可以在创建该堆栈时独立选择


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



然后我发现了如果你在早期的Java 6版本上运行,那么源代码中的错误可能是有意义的:



http://bugs.java.com/view_bug.do?bug_id=6316197


I have a program which will run into a very deep recursion while executing. In middle of this, I am getting java.lang.StackOverflowError and my application freezes. I am using JDK 1.6 and Windows 7 OS.

Strange thing here is, I am not getting this StackOverflowError with same code base while running my application with Java 1.5 and Windows XP. I understood that default stack size will differ from platform to platform and OS to OS. But with Java 1.5 and Windows XP, I set stack size of 256k using -Xss command and not getting this error. With same 256k in Windows 7 OS and Java 1.6, I am getting this error.

With stack size of 256k, my application is running without any issue in Windows XP and it's throwing a StackOverflowError in Windows 7 OS.

So please give any information how thread stack sizes will differ from Windows 7 OS to Windows XP??

解决方案

I think the answer is, that the JDK 1.5 ignores setting the default stack size to a specific value. Say, if you have a default stack size of 512K and (you believe that) you set it to 256K, finally it will still have a value of 512K. With the JDK 6 you also set the default size to 256K, but here it really will have this value. That could be the reason, why your Windows 7 is getting the error (earlier)!


Look at this -Xss Default Values table:

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 

Here you can see, that the default values differ to the platform you're running on.

See: http://docs.oracle.com/cd/E13150_01/jrockit_jvm/jrockit/jrdocs/refman/optionX.html#wp1024112

Furthermore, because you're getting a StackOverflowError on one system, but not the other, a 32-bit VM will store addresses with 4 bytes of memory. A 64-bit VM will store the same with 8-bytes! So, assuming you set the stack size value to 256K (yes, it's kBytes), a 32-bit system (probably your XP system) can store 65,536 addresses in its stack memory. A 64-bit system (your Windows 7 system) is only be able to store 32,768 addresses. This could be the issue between these two systems.

In general, Java objects consuming the same size of memory in a 32 as in a 64-bit VM. Obviously, if you have an Object which is referencing to 100 other Objects, it will increase the size of the main Object by 400 bytes on a 64-bit JVM.

Additionally it is said:

Note that on some versions of Windows, the OS may round up thread stack sizes using very coarse granularity. If the requested size is less than the default size by 1K or more, the stack size is rounded up to the default; otherwise, the stack size is rounded up to a multiple of 1 MB.

64k is the least amount of stack space allowed per thread.

See: http://www.oracle.com/technetwork/java/hotspotfaq-138619.html#threads_oom

Unfortunately, I didn't find any concrete explanation, how the coarse granularity is being expressed.

Try to run the following sample program on both platforms to guess, how much the stack sizes differ between each other:

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);
        }
    }
}

The results on my machine are:

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

(It would be great, if the list can be extended from other systems you're running on!)

As you can see, the stack sizes are a complete mystery. It can be the fact, that the different Java versions consume different spaces in the stack memory.

Furthermore, if you set the stack size with -Xss, the value will be ignored on a Java 5 release.

With the JDK 7, you're not getting always the same result like on the other releases. The same goes to the JDK 8, where the ranges differ substantially.

Perhaps you can figure out yourself, if it only differs slighty or not on your own systems.

Further reading: http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-2.html#jvms-2.5.2

This specification permits Java Virtual Machine stacks either to be of a fixed size or to dynamically expand and contract as required by the computation. If the Java Virtual Machine stacks are of a fixed size, the size of each Java Virtual Machine stack may be chosen independently when that stack is created.

So, the question is, what is meant by dynamically expand?

Then I discovered a bug in the sources, that could be of interest, if you're running on an earlier Java 6 release:

http://bugs.java.com/view_bug.do?bug_id=6316197

这篇关于使用Java 1.6和Windows 7 OS进行深度递归时出现java.lang.StackOverflowError的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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