什么实际上导致堆栈溢出错误?
这个问题在这里已经有了答案:
看起来你认为一个stackoverflow错误就像本地程序中的缓冲区溢出异常,当存在写入未分配给缓冲区的内存的风险,从而破坏其他一些内存位置时。 事实并非如此。
JVM为每个线程的每个堆栈分配一个给定的内存,如果尝试调用某个方法来填充此内存,则JVM将引发错误。 就像它试图在长度为N的数组的索引N处写入一样。不会发生内存损坏。 堆栈不能写入堆中。
StackOverflowError是Stack的一个OutOfMemoryError堆栈:它只是表示没有更多的内存可用。
虚拟机错误说明(第6.3节)
StackOverflowError :Java虚拟机实现已经耗尽了线程的堆栈空间,通常是因为线程正在执行无限数量的递归调用,因为执行程序中存在错误。
没有其他方法可以发生堆栈溢出,不仅通过递归?
当然。 只要继续调用方法,永不返回。 但是,除非允许递归,否则您需要很多方法。 实际上,它并没有什么区别:一个堆栈帧是一个堆栈帧,不管它是递归方法之一还是不相同。
第二个问题的答案是:当JVM尝试为下一次调用分配堆栈帧并检测到不可能时,检测到stackoverflow。 所以,什么都不会被覆盖。
没有其他方法可以发生堆栈溢出,不仅通过递归?
挑战接受:) StackOverflowError
没有递归(挑战失败,见评论):
public class Test
{
final static int CALLS = 710;
public static void main(String[] args)
{
final Functor[] functors = new Functor[CALLS];
for (int i = 0; i < CALLS; i++)
{
final int finalInt = i;
functors[i] = new Functor()
{
@Override
public void fun()
{
System.out.print(finalInt + " ");
if (finalInt != CALLS - 1)
{
functors[finalInt + 1].fun();
}
}
};
}
// Let's get ready to ruuuuuuumble!
functors[0].fun(); // Sorry, couldn't resist to not comment in such moment.
}
interface Functor
{
void fun();
}
}
使用标准javac Test.java
编译并使用java -Xss104k Test 2> out
。 之后, more out
会告诉你:
Exception in thread "main" java.lang.StackOverflowError
第二次尝试。
现在这个想法更简单了。 Java中的基元可以存储在堆栈中。 所以,我们宣布很多双打,比如double a1,a2,a3...
该脚本可以为我们编写,编译和运行代码:
#!/bin/sh
VARIABLES=4000
NAME=Test
FILE=$NAME.java
SOURCE="public class $NAME{public static void main(String[] args){double "
for i in $(seq 1 $VARIABLES);
do
SOURCE=$SOURCE"a$i,"
done
SOURCE=$SOURCE"b=0;System.out.println(b);}}"
echo $SOURCE > $FILE
javac $FILE
java -Xss104k $NAME
而且......我有些意想不到的事情:
#
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x00007f4822f9d501, pid=4988, tid=139947823249152
#
# JRE version: 6.0_27-b27
# Java VM: OpenJDK 64-Bit Server VM (20.0-b12 mixed mode linux-amd64 compressed oops)
# Derivative: IcedTea6 1.12.6
# Distribution: Ubuntu 10.04.1 LTS, package 6b27-1.12.6-1ubuntu0.10.04.2
# Problematic frame:
# V [libjvm.so+0x4ce501] JavaThread::last_frame()+0xa1
#
# An error report file with more information is saved as:
# /home/adam/Desktop/test/hs_err_pid4988.log
#
# If you would like to submit a bug report, please include
# instructions how to reproduce the bug and visit:
# https://bugs.launchpad.net/ubuntu/+source/openjdk-6/
#
Aborted
这是100%重复。 这与你的第二个问题有关:
StackOverflowError在JVM实际溢出之前还是之后发生?
所以,在OpenJDK 20.0-b12的情况下,我们可以看到JVM首先爆炸了。 但它看起来像一个错误,也许有人可以在评论中确认,因为我不确定。 我应该报告吗? 也许它已经修复了一些更新的版本......根据JVM规范链接(由JB Nizet在评论中给出)JVM应该抛出StackOverflowError
,而不是死亡:
如果线程中的计算需要比允许的更大的Java虚拟机堆栈,Java虚拟机会引发StackOverflowError。
第三次尝试。
public class Test {
Test test = new Test();
public static void main(String[] args) {
new Test();
}
}
我们要创建新的Test
对象。 所以,它的(隐式)构造函数将被调用。 但是,在此之前, Test
所有成员都已初始化。 所以, Test test = new Test()
首先被执行...
我们想创建新的Test
对象...
更新:运气不好,这是递归,我在这里问了关于这个问题。
链接地址: http://www.djcxy.com/p/14125.html上一篇: What actually causes a Stack Overflow error?
下一篇: Avoiding stack overflows by allocating stack parts on the heap?