2012-05-07 22 views
3

對於Java函數聲明:在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 

00002aab04685ff800002aab04685ff0接近,似乎堆棧增長過快。我試圖調查這部分代碼,並懷疑這是多少次調用此函數時出現問題的原因。如果堆被堆上的某些變量引用,堆棧可能不會被清除?

回答

5

問題是否涉及特定的對象堆是有點涉及。

一般來說,在Java中,所有對象都分配在堆上,因爲方法可能會返回或存儲指向某個對象的指針。如果該對象已經放在堆棧中,則在下一次將堆棧幀放入堆棧時將覆蓋它。

但是,HotSpot JIT編譯器會執行一些名爲Escape Analysis的操作。該分析通過查看其實現來發現對象是否「逃避」了方法的範圍。如果對象不是轉義,編譯器可以安全地將它分配到堆棧上。

維基百科有關於Escape Analysis in Java的更多信息,關於多線程和鎖定。


關於堆棧溢出:堆棧調用堆棧上幀總是除去方法完成之後。實際上,甚至沒有必要明確刪除它。下一幀將會覆蓋之前的內容。

另外,儘管在其他語言(如C)中,通過在堆棧中放置非常大的對象可能導致堆棧溢出,但我不認爲這可能發生在Java中。我期望Sun(Oracle)的工程師足夠聰明,不會讓VM在堆棧中存儲巨大的對象。

所以堆棧溢出的唯一可能性是嵌套的方法調用太多。由於堆棧空間足夠大以處理任何「正常」方法調用嵌套,堆棧溢出通常意味着代碼中的無限(或非常大)遞歸。

+0

爲什麼會這樣做?我同意,從堆棧中獲取某些東西比從堆中獲取更快,但是在CPU每秒執行數十億次操作的時候真的很重要嗎? –

+2

有很多原因希望堆棧上有對象:首先,堆棧有更高的可能性存在於緩存中,爲您提供本地變量的緩存局部性。其次,堆上的對象越少,垃圾收集器就越不忙碌。第三,堆棧中的對象保證只能由一個線程訪問,所以不需要鎖定它們。 – rolve

+0

所以,你認爲我發佈的代碼不是問題的原因,對吧? –

0

nameisDoneoutABC和 「指針」,以匿名someFunction都將在堆棧;其餘的去堆。

+1

如果有更多的散文比這更酷 - 原始海報不能從這個答案中學**任何東西。 – Romain

+0

如果函數被多次調用,會發生堆棧溢出,因爲它們中的一些被堆中的對象引用? –

+0

@Harold這是一個完全不同的問題。堆棧溢出只是由堆棧中的對象引起的。 [你可以閱讀這個。](http://stackoverflow.com/questions/214741/what-is-a-stack-overflow-error) – UmNyobe

相關問題