2016-04-27 19 views
17

Java應用程序爲所有線程啓動一個堆。每個線程都有自己的堆棧。Java(JVM)如何爲每個線程分配堆棧

當Java應用程序啓動時,我們使用JVM選項-Xms-Xmx來控制堆的大小,並使用-Xss來控制堆棧大小。

我的理解是,被創建的堆成爲JVM的「託管」內存,並且所有正在創建的對象都被放置在那裏。

但是,堆棧創建如何工作? Java是否在創建每個線程時創建一個堆棧?如果是這樣,堆棧在內存中的位置?它當然不在「被管理」的堆中。

JVM是從本地內存創建堆棧還是預先爲堆棧預分配一部分管理內存區域?如果是這樣,JVM如何知道如何創建線程?

+1

您可能會發現[此答案](http://stackoverflow.com/a/25318740/2032064)interresting – Mifeet

回答

4

JVM使用的內存不僅僅是堆。例如Java方法, 線程堆棧和本地句柄被分配在獨立於 堆的內存中,以及JVM內部數據結構。

Further reading

因此,要回答你的問題:

不Java中創建爲每個線程堆棧被創建的時候嗎?

是的。

如果是這樣,堆棧在內存中的位置?

在JVM分配的內存中,但不在堆上。

如果是這樣,JVM如何知道如何創建線程?

它沒有。

您可以創建多達你想,直到你已經刷爆你的JVM內存並獲得

Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread 

編輯:

上述所有指 JVM,但我發現很難相信其他JVM在這些基本問題上會有所不同。

+0

此外,雖然這些都是很好的答案,但這是JVM的內部規範。以上任何情況都可能隨時發生變化。它不應該也不重要,因爲JVM如何執行其工作。讓JVM決定如何最好地管理其資源。 – markspace

+0

是的,但這並不意味着要找出HotSpot如何做並不有趣。 – Mifeet

+0

@markspace謝謝,用特定的'JVM'更新了我的答案,但是你真的認爲有'JVM'在這些問題上採取不同的行爲嗎? – Daniel

30

有關Java specification告訴我們的線程堆棧有幾件事情。其中包括:

  • 每個Java虛擬機線程都有一個私有Java虛擬機堆棧,與該線程同時創建。

  • 由於Java虛擬機堆棧從來沒有被直接操作,除了推送和彈出幀之外,幀可能是堆分配的。 Java虛擬機堆棧的內存不需要是連續的。

  • 規範允許Java虛擬機堆棧要麼具有固定的大小,要麼根據計算的需要動態擴展和收縮。

現在,如果我們關注諸如HotSpot等JVM實現,我們可以獲得更多信息。以下是我從不同來源收集到的一些事實:

  • HotSpot中線程的最小堆棧大小似乎是固定的。這就是前面提到的-Xss選項。 (Source)

在Java SE 6,在Sparc默認爲512K在32位VM,並且在1024K 64位VM。 ...您可以通過使用-Xss選項運行來減少堆棧大小。 ... 64k是每個線程允許的最小堆棧空間量。

  • JRockit從堆棧所在的堆中分配內存。 (Source)

注意,JVM使用更多的內存比剛堆。例如,Java方法,線程堆棧和本地句柄分配在獨立於堆的內存中,以及JVM內部數據結構中。

  • 有Java線程和熱點區域的原生操作系統線程之間的直接映射。 (Source)

  • 但HotSpot中的Java線程堆棧是軟件管理的,它不是OS本地線程堆棧。 (Source)

它使用單獨的軟件堆棧來傳遞Java參數,而本地C堆棧用於由虛擬機本身。許多JVM內部變量(如程序計數器或Java線程的堆棧指針)都存儲在C變量中,這些變量不保證始終保存在硬件寄存器中。這些軟件解釋器結構的管理佔總執行時間的相當大的份額。

  • JVM還利用用於本機方法和JVM運行時調用(例如類加載)相同的Java線程堆棧。 (Source)。有趣的是,即使分配的對象有時也可能位於堆棧上而不是堆上作爲性能優化。(Source)

JVM可以使用一種稱爲逃逸分析技術,通過它們可以告訴某些對象保持侷限於其整個壽命單個線程,而且壽命由給定疊層的壽命爲界幀。這些對象可以安全地分配到堆棧而不是堆上。

而且因爲圖像是勝過千言萬語,這裏是從James BloomJava memory


一個現在回答大家的一些問題:

如何JVM知道如何可能線程會被創建?

它沒有。通過創建可變數量的線程可以很容易地通過矛盾來證明。它確實對線程的最大數量和每個線程的堆棧大小做了一些假設。這就是爲什麼如果分配過多的線程,你可能會耗盡內存(而不是堆內存!)。

Java是否在創建每個線程時創建一個堆棧?

如前所述,每個Java虛擬機線程都有一個私有Java虛擬機堆棧,與該線程同時創建。(Source)

如果是這樣,堆棧在內存中的位置?它當然不在「被管理」的堆中。

如上所述,從技術上講,Java specification允許堆棧內存存儲在堆上。但至少JRockit JVM使用不同的內存部分。

JVM是從本地內存創建堆棧還是預先爲堆棧預分配一部分管理內存區域?

棧是JVM管理,因爲Java規範prescribes如何必須表現:Java虛擬機堆棧存儲幀(§2.6)。 Java虛擬機堆棧類似於傳統語言堆棧。用於native方法的本機方法堆棧有一個例外。更多關於這個在the specification

+1

那麼,大部分是在[JVM規範](https://docs.oracle.com/javase/specs/jvms/se8/html/)中定義的,不是? AFAIK,GC是從規格中排除的區域。 –

+1

你說得對,JVM規範中比我想象的要多。我在此期間更新了我的答案。 – Mifeet

+0

所以,如果我有一個512MB的堆,如果我創建1000個線程(顯然它大於512MB),它佔用了我的堆的內存,因此OOM異常或額外的內存空間在操作系統? – Jaskey