1、java虛擬機棧(java virtual machine stacks)也是線程私有的,它的生命週期與線程相同。虛擬機棧描述的是java方法執行的內存模型:每一個方法被執行的時候都會同時建立一個棧幀(stack frame)用於存儲局部變量表、操做棧、動態連接、方法出口等信息。每個方法被調用直至執行完成的過程,就對應着一個棧幀在虛擬機棧中從入棧到出棧的過程。
常常有人把java內存區分爲堆內存(Heap)和棧內存(Stack),這種分法比較粗糙,java內存區域的劃分其實遠比這複雜。這種流行方式的劃分只能說明大多數程序員最關注的、與對象內存分配關係最密切的內存區域是這兩塊。其中所指的「棧」就是虛擬機棧,或者說是虛擬機棧中的局部變量表部分。
局部變量表存放了編譯期可知的各類基本數據類型(boolean、byte、char、short、int、float、long、double)、對象引用(reference類型,它不等同於對象自己,根據不一樣的虛擬機實現,它多是一個指向對象起始地址的引用指針,也可能指向一個表明對象的句柄或者其餘與此對象相關的位置)和returnAddress類型(指向了一條字節碼指令的地址)。
其中64位長度的long和double類型的數據會佔用2個局部變量空間,其他的數據類型只佔用一個。局部變量表所需的內存空間在編譯期間完成分配。當進入一個方法時,這個方法須要在幀中分配多大的局部變量空間是徹底肯定的,在方法運行期間不會改變局部變量表的大小。
在java虛擬機規範中,對這個區域規定了2種異常狀況:若是線程請求的棧深度大與虛擬機所容許的深度,將拋出StackOverFlowError異常;若是虛擬機棧能夠動態擴展,當擴展時沒法申請到足夠的內存時會拋出OutOfMemoryError異常。
2、 對於大多數應用來講,java堆(java Heap)是java虛擬機所管理的內存中最大的一塊。Java堆是被全部線程共享的一塊內存區域,在虛擬機啓動時建立。此內存區域的惟一目的就是存放對象實例,幾乎全部的對象實例都在這裏分配內存。這一點在java虛擬機規範中的描述是:全部的對象實例以及數組都要在堆上分配,可是隨着JIT編譯器的發展與逃逸分析技術的逐漸成熟,棧上分配、標量替換優化技術將會致使一些微妙的變化發生,全部的對象都分配在堆上也逐漸變得不是那麼「絕對」了。
Java堆是垃圾收集器管理的主要區域,所以不少時候也被稱爲「GC」堆。若是從內存回收的角度看,因爲如今收集器基本都是採用的分代收集算法,因此java堆中還能夠細分爲:新生代和老生代;再細緻一點的有Eden空間、From Survivor空間、To Survivor空間等。若是從內存分配的角度看,線程共享的java堆中可能劃分出多個線程私有的分配緩衝區(Thread Local Allocation Buffer,TLAB)。不過,不管如何劃分,都與存放內容無關,不管哪一個區域,存儲的都仍然是對象實例,進一步劃分的目的是爲了更好的回收內存,或者更快的分配內存。
根據java虛擬機規範的規定,java堆能夠處於物理上不連續的內存空間中,只要邏輯上是連續的便可,就像咱們的磁盤空間同樣。在實現時,既能夠實現成固定大小的,也能夠是可擴展的,不過當前主流的虛擬機都是按照可擴展來實現的。若是在堆中沒有內存完成實例分配,而且堆也沒法再擴展時,將會拋出OutOfMemoryError異常。
java