2010-09-05 17 views
49

我只知道非基元(對象)放在堆上,而方法放在堆棧上,但是基元變量呢?Java基元是在棧還是在堆上?

--update

基礎上的答案,我可以說堆能有一個給定對象的新棧和堆?鑑於該對象將有原始和參考變量..?

+1

每個線程都有自己的堆棧,而不是每個對象。如果只有一個線程,那麼只有一個棧。 – Alex 2016-10-29 01:45:59

回答

77

本地定義的原語將在堆棧中。然而,如果一個基元被定義爲一個對象的一個​​實例的一部分,那麼這個基元就會在堆上。

public class Test 
{ 
    private static class HeapClass 
    { 
     public int y; // When an instance of HeapClass is allocated, this will be on the heap. 
    } 
    public static void main(String[] args) 
    { 
     int x=1; // This is on the stack. 
    } 
} 

至於更新:

對象沒有自己的堆棧。在我的例子中,int y實際上是HeapClass的每個實例的一部分。每當分配HeapClass實例(例如new HeapClass())時,HeapClass的所有成員變量都會添加到堆中。因此,由於HeapClass的實例正在堆中分配,所以int y將作爲HeapClass的實例的一部分堆在堆上。

但是,在任何方法的主體中聲明的所有基元變量都將在堆棧中。

正如您在上面的示例中看到的,int x在堆棧中,因爲它在方法體中聲明 - 而不是作爲類的成員。

+0

+1謝謝!請考慮我對該問題的新更新。 – 2010-09-05 16:00:28

+1

您可能想要更改代碼中的註釋。在文本中,你說'x'在堆棧上,但註釋表示堆。 – musiKk 2010-09-05 16:58:44

+0

好的。謝謝。 – 2010-09-05 19:35:59

19

所有局部變量(包括方法參數)都在棧上;對象及其所有字段都存儲在堆中。變量總是原語或引用到對象。

Java實現可能實際上將對象存儲在堆上,使得它仍然符合規範。同樣,局部變量可以存儲在寄存器中,或者通過優化變得模糊不清。

+0

+1謝謝!請考慮我對該問題的新更新。 – 2010-09-05 15:59:50

10

可以在兩處找到基元。

class Foo 
{ 
    public int x; 
    public static void Main() 
    { 
     int y = 3; // y is on the stack 
     Foo f = new Foo(); // f.x is probably on the heap 
    } 
} 

除非你不應該真正關心,除非你正在構建一個JVM。一個非常聰明的優化器可能會決定,因爲F指出永遠不會轉義Main,並且永遠不會傳遞給另一個函數,因此可以安全地將其分配到堆棧上。

至於更新:

的棧和堆不受什麼是存儲在其中,但爲他們提供相當的操作區別開來。該堆棧允許您以LIFO方式分配一塊內存,直到所有比它年輕的塊都被釋放爲止,您無法取消分配一塊。這很方便地與調用堆棧的使用方式一致。只要你的函數返回時,你可以把任何東西放在堆棧上。這是一個優化,因爲它只支持以這種方式使用,所以從堆棧中分配和釋放非常快。如果需要,可以在實現中將函數的所有局部變量存儲在堆中。堆更靈活,因此使用起來更昂貴。如我所說,一個對象有一個堆棧和一個堆是不正確的,但是堆棧和堆的區別並不在於它是什麼,而是可用的操作。

+0

+1謝謝!請考慮我對該問題的新更新。 – 2010-09-05 16:01:03

+0

@logan:''f.x可能在堆上 - >你是說它取決於JVM的實現嗎? – realPK 2017-03-10 16:34:41

7

原始值在堆棧上分配,除非它們是一個對象的字段,在這種情況下,它們將放在堆上。堆棧用於評估和執行,因此不要說具有原始字段的對象具有堆棧 - 它仍被認爲是堆的一部分。即使Stack對象也被分配在堆上。

相關問題