4

对于 Java 函数中的语句:

Xxx xxx = new Xxx() {
    public Abc abc(final Writer out) {
        return new SomeFunction(out) {
            boolean isDone = false;
            public void start(final String name) {
                /* blah blah blah */
            }
        };
    }
};

哪些变量,包括函数,放在堆上,哪些将放在堆栈上?

我问这个的原因是 JVM 中的分段错误:

kernel: java[14209]: segfault at 00002aab04685ff8 rip 00002aaab308e4d0 rsp 00002aab04685ff0 error 6

00002aab04685ff8并且00002aab04685ff0接近了,似乎堆栈增长太快了。我尝试排查这部分代码,多次调用该函数时怀疑是否是问题的原因。如果堆上的某些变量引用了堆栈,是否有可能没有清除堆栈?

4

2 回答 2

5

一个特定对象是否在堆上的问题有点复杂。

一般来说,在 Java 中,所有对象都分配在堆上,因为方法可能返回或存储指向该对象的指针。如果该对象已被放入堆栈,则在下一次将堆栈帧放入该堆栈时,它将被覆盖。

但是,HotSpot JIT 编译器会执行称为Escape Analysis的操作。此分析通过查看方法的代码来确定对象是否“逃脱”了方法的范围。如果一个对象没有转义,编译器可以安全地将它分配到堆栈上。

维基百科有更多关于Java 逃逸分析的信息,还有关于多线程和锁定的信息。


关于堆栈溢出:调用堆栈上的堆栈帧总是在方法完成后被删除。实际上,甚至不需要显式删除它。下一帧将覆盖之前的内容。

此外,尽管在其他语言(如 C)中,通过将非常大的对象放在堆栈上可能会导致堆栈溢出,但我认为这在 Java 中不会发生。我希望 Sun (Oracle) 的工程师足够聪明,不会让 VM 在堆栈上存储大量对象。

因此,堆栈溢出的唯一可能性是嵌套方法调用过多。由于堆栈空间足够大,可以处理任何“正常”的方法调用嵌套,因此堆栈溢出通常表示代码中存在无限(或非常大)递归。

于 2012-05-07T12:11:15.850 回答
0

name, isDone, out,ABC和指向匿名的“指针”someFunction都将在堆栈上;其余的进入堆。

于 2012-05-07T11:50:21.617 回答