Java虛擬機(JVM)內存區域

        Java虛擬機內存區域分爲五部分:程序計數器、Java虛擬機棧、本地方法棧、堆、方法區。其中程序計數器、Java虛擬機棧、本地方法棧屬於線程私有內存區,其生命週期與線程相同,隨線程的產生而產生,隨線程的消亡而消亡。這幾個區域的內存在方法或線程結束時,天然就跟着回收了。所以這三個區域的內存分配和回收具備肯定性,不須要考慮內存回收的問題。而Java堆和方法區屬於線程共享內存區,全部線程均可以訪問。只有在程序運行期間才能知道建立哪些對象,所以這兩個區域的內存分配和回收都是動態的,也是垃圾收集器收集的主要區域。html

 

 

        下面分別介紹這五個區域。程序員

       1)       程序計數器

        程序計數器是一塊較小的內存空間,能夠當作線程執行的字節碼行號指示器。字節碼解釋器工做的時候就是經過改變程序計數器的值,來選取下一條所要執行的字節碼指令,分支、跳轉、循環、異常處理、線程恢復等都須要依賴程序計數器來完成。程序計數器是Java虛擬機中惟一不會發生內存溢出(OutOfMemoryError)的區域。數組

        Java虛擬機的多線程是經過線程間的輪流切換並分配處理器執行時間的方式來完成的,任意時刻一個處理器只會執行一條線程中的指令。爲了使線程切換後能恢復到正確的執行位置,每一個線程都有一個獨立的程序計數器,各線程之間獨立存儲、互不影響,所以是線程私有內存區。多線程

        2)       Java虛擬機棧

        Java虛擬機棧描述的是Java方法執行的內存模型:每一個方法在執行時都會建立一個棧幀用於存儲局部變量表、操做數棧、動態連接、方法出口等信息。每一個方法從調用到執行結束都伴隨着一個棧幀在虛擬機棧中從入棧到出棧的過程。學習

        Java虛擬機棧也是線程私有內存區,生命週期與線程相同。基於棧的內存區域均可能發生兩種異常:棧溢出和內存溢出。若是線程請求棧的深度大於虛擬機棧所容許的最大深度,而且沒法擴展時,將會發生棧溢出(StackOverflowError)異常;若是能夠擴展,在擴展時沒法申請到足夠的內存,將會發生棧溢出(OutOfMemoryError)異常。spa

        局部變量表用於存放方法參數和方法內部定義的局部變量,其數據類型是編譯期可知的各類基本數據類型、對象引用類型(reference)和返回(returnAddress)類型(它指向了一條字節碼指令的地址)。局部變量表所需的內存空間在編譯期間完成分配,即在Java程序被編譯成Class文件時,就肯定了所需分配的最大局部變量表的容量。當進入一個方法時,這個方法須要在棧中分配多大的局部變量空間是徹底肯定的,在方法運行期間不會改變局部變量表的大小。操作系統

        3)       本地方法棧

         本地方法棧與虛擬機棧所發揮的做用很是類似,只是虛擬機棧爲虛擬機執行Java方法服務(即程序員本身寫的方法),而本地方法棧則爲使用到的本地操做系統(Native)方法服務。本地方法棧也是基於棧,所以也會發生棧溢出或內存溢出異常。線程

        4)       Java堆

        Java堆是虛擬機所管理的最大一塊內存,是全部線程共享的一塊內存區域,在虛擬機啓動時建立。Java堆用來存放對象實例,幾乎全部的對象實例和數組都在這裏分配內存。Java堆是垃圾收集器管理的主要區域,所以不少時候也被稱爲「GC堆」。htm

        Java堆能夠處於物理上不連續的內存空間中,只要邏輯上連續便可。在實現時,既能夠是固定大小的,也能夠是可擴展的,目前主流虛擬機都是可擴展的。若是在堆中沒有足夠的內存可分配,且沒法擴展時,將會拋出內存溢出異常。對象

        從垃圾收集的角度來看,Java堆還能夠細分爲新生代和老年代。新生代包括Eden、Survivor from、Survivor to,詳情請見下面下面一章。

        5)       方法區

        方法區也是線程共享的內存區域,用於存儲被虛擬機加載的類的信息、常量、靜態變量、即時編譯器編譯後的代碼等數據。

        和堆同樣,方法區一樣能夠處於物理上不連續的內存空間中,只要邏輯上連續便可。在實現時,既能夠是固定大小的,也能夠是可擴展的。方法區能夠不進行垃圾收集,相對而言,方法區的垃圾收集行爲不多,主要是對常量池的回收和對類型的卸載。當方法區沒有足夠的內存完成分配時,會發生內存溢出異常。

        平時所說的「永久代」(PermGen space)指的是方法區。

        「運行時常量池」是方法區的一部分,用於存放編譯期生成的各類字面量和符號引用。運行時常量池具備動態性,常量既能夠在編譯期產生並進入常量池,也能夠在運行期間進入常量池,常見的是String類的intern()方法。運行時常量池是方法區的一部分,所以也會發生內存溢出異常。

 

        轉載請註明出處 https://www.cnblogs.com/Y-oung/p/9762682.html

        工做、學習、交流或有任何疑問,請聯繫郵箱:yy1340128046@163.com

相關文章
相關標籤/搜索