使用Java 1.6和Windows 7 OS进行深度递归时出现java.lang.StackOverflowError [英] java.lang.StackOverflowError while doing deep recursion with Java 1.6 and Windows 7 OS
问题描述
我有一个程序在执行时会遇到非常深的递归。在这个中间,我得到 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 Object
s, 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屋!