版權聲明:本文爲博主原創文章,轉載請註明出處,歡迎交流學習!算法
咱們都知道,當虛擬機執行Java代碼的時候,首先要把字節碼文件加載到內存,那麼這些類的信息都存放在內存中的哪一個區域呢?當咱們建立一個對象實例的時候,虛擬機要爲對象分配內存,Java虛擬機又是如何配份內存的呢?這些都涉及到Java虛擬機的內存劃分機制,今天咱們就來探究一下Java虛擬機的內存模型。數據結構
Java虛擬機在執行Java程序的過程當中會把它所管理的內存劃分爲若干個不一樣的數據區域,這些區域都有各自的用途以及建立和銷燬的時間,有的區域隨着虛擬機進程的啓動而存在,有些區域則依賴用戶線程的啓動和結束而創建和銷燬。根據Java虛擬機規範的規定,Java虛擬機所管理的內存包括如下幾個數據區域。以下圖所示:多線程
以上就是Java虛擬機運行時數據區域的劃分,每一塊內存區域都有它的職責,存放着不一樣的運行時數據。學習
虛擬機棧
spa
Java虛擬機棧是線程私有的,每個線程在這個區域都有一塊所屬的內存區域,它的生命週期與線程相同,隨線程啓動而生,隨線程消亡而滅。虛擬機棧描述的是Java方法執行的內存模型,每個線程都對應着虛擬機棧區域裏的一個棧數據結構,因爲一個線程的方法調用鏈可能會很長,每個方法在執行時都會建立一個棧幀,棧幀就是線程對應的棧數據結構的棧元素,棧幀用於存儲局部變量表、操做數棧、動態連接等信息。局部變量表存放了方法參數和方法內部定義的局部變量,包括各類基本數據類型和對象引用類型等信息。常常聽到有的程序猿粗糙的把虛擬機內存劃分爲堆內存和棧內存,這種劃分只能說明大多數程序猿比較關注的、與對象內存分配關係最密切的是這兩塊內存區域,其中的「棧內存」就是這裏所說的虛擬機棧,而虛擬機棧裏咱們程序猿最爲關注的就是局部變量表部分。
線程
本地方法棧對象
本地方法棧也是線程私有的,它與虛擬機棧發揮的做用類似,它們之間的區別不過是虛擬機棧爲虛擬機執行Java方法服務,而本地方法棧則爲虛擬機使用到的Native方法(本地方法)服務。在Java虛擬機規範中並無對本地方法棧的實現作強制規定,有的虛擬機甚至直接把虛擬機棧和本地方法棧合二爲一。blog
堆生命週期
Java堆是全部線程所共享的一塊內存區域,也是Java虛擬機所管理的內存中最大的一塊。這塊內存的惟一目的就是存放對象實例,幾乎全部的對象實例都在這裏分配內存。Java堆是垃圾收集器管理的主要區域,從內存回收的角度看,因爲如今收集器基本都採用分代收集算法,因此Java堆還能夠細分爲新生代和老年代。新生代還能夠再細分爲Eden區域、FromSurvivor區域和ToSurvivor區域。不管怎麼劃分,都與存放的內容無關,存儲的任然都是對象實例。進一步劃分的目的是爲了更好的回收或者更快的分配內存。進程
方法區
方法區與Java堆同樣,是線程共享的內存區域,它用於存儲已被虛擬機加載的類信息、常量、靜態變量、編譯器編譯後的代碼等數據。方法區是一個邏輯區,具體屬於哪一塊物理內存根據不一樣的虛擬機實現而定。在HotSpot的實現中,方法區邏輯上與堆內存隔離,物理存儲上倒是是屬於Java堆的一部分。不少人把方法區稱爲「永久代」,實際上是HotSpot使用永久代來實現方法區而已。其餘的虛擬機實現並無永久代這一律念。Java虛擬機規範對方法區的限制很是寬鬆,除了和Java堆同樣不須要連續的內存和能夠選擇固定大小或者可擴展外,還能夠選擇不實現垃圾回收。通常來講不會在方法區進行垃圾回收,在這一區域進行回收的效果很難讓人滿意。當方法區沒法知足內存分配需求時會拋出內存溢出異常。
運行時常量池是方法區的一部分,用於存放編譯期間生成的各類字面量和符號引用,這部份內容將在類加載後進入方法區的運行時常量池中存儲。
程序計數器
程序計數器是一塊很小的內存空間,它也是線程私有的。它能夠看做是當前線程所執行的字節碼的行號指示器,經過改變這個計數器的值來選取下一行須要執行的字節碼指令。因爲Java虛擬機的多線程是經過線程輪流切換並分配處理器執行時間的方式來實現的,在任何一個肯定的時刻,一個處理器內核只會執行一條線程中的指令,所以,爲了線程切換後可以恢復到正確的執行位置,每條線程都須要有一個獨立的程序計數器,各條線程之間互不影響,獨立存儲。
以上就是Java虛擬機的內存模型劃分,這是咱們程序猿必須掌握的原理,弄清Java虛擬機的內存模型,是理解虛擬機內存分配和垃圾回收的基礎,以此做爲總結。