对于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
近在咫尺,似乎堆栈增长太快了。我尝试研究这部分代码,并怀疑它是多次调用此函数时是否是问题的原因。如果堆被堆上的某些变量引用,堆栈是否可能被清除?
答案 0 :(得分:5)
特定对象是否在堆上的问题有点涉及。
通常,在Java中,所有对象都在堆上分配,因为方法可以在某处返回或存储指向对象的指针。如果对象已经放在堆栈上,那么下次堆栈帧放在那里时就会覆盖它。
然而,HotSpot JIT编译器执行了一个名为Escape Analysis的操作。此分析通过查看其实现来查明对象是否“逃避”该方法的范围。如果对象不转义,编译器可以安全地在堆栈上分配它。
维基百科有关于Escape Analysis in Java的更多信息,也有关于多线程和锁定的信息。
关于堆栈溢出:方法完成后,调用堆栈上的堆栈帧始终被删除。实际上,甚至没有必要明确删除它。下一帧将覆盖以前的帧。
此外,虽然在其他语言(如C)中,通过在堆栈上放置非常大的对象可能导致堆栈溢出,但我认为这不会发生在Java中。我希望Sun(Oracle)的工程师足够聪明,不要让VM在堆栈中存储大量对象。
因此,堆栈溢出的唯一可能性是拥有太多嵌套方法调用。由于堆栈空间非常大,足以处理任何“普通”方法调用嵌套,因此堆栈溢出通常意味着代码中的无限(或非常大)递归。
答案 1 :(得分:0)
name
,isDone
,out
,ABC
和匿名someFunction
的“指针”都将出现在堆栈中;剩下的就是堆。